你從未知道如此強大的ASP.NET MVC DefaultModelBinder


看到很多ASP.NET MVC項目還在從request.querystring或者formContext里面獲取數據,這實在是非常落后的做法。也有的項目建了大量的自定義的modelbinder,以為很牛,實際上也落后的很。

 

ASP.NET MVC提供了IModelBinder的默認實現,這個實現的類就叫DefaultModelBinder。我們在寫代碼的時候,幾乎感覺不到這個類的存在,因為這個類自動將request信息解析成action參數。本文將向大家展示這個類是多么強大,可以拯救大量的代碼。

 

先看個例子。假如有如下表單,用於編輯用戶信息以及該用戶的時間表。在這個例子中,我要利用DefaultModelBinder自動將整個表單數據解析成復雜實體類的實例。一行手工解析的C#代碼都不用寫。

 

 

對應的controller的代碼如下,很簡單:

 1 public class DemoController : PublicControllerBase
 2 {
 3     public ActionResult UserEditor()
 4     {
 5         return View();
 6     }
 7 
 8     [HttpPost]
 9     public string SaveUser(DemoUser user)
10     {
11         var result = string.Empty;
12         if (user != null)
13         {
14             result = Serializer.ToJson(user);
15         }
16         return result;
17     }
18 }

 

相關的實體類的定義,也很簡單:

public class DemoUser
{
    public string Username { get; set; }
    public string Email { get; set; }
    public string Language { get; set; }
    public Gender Gender { get; set; }
    public int[] RoleIds { get; set; }
    public List<ScheduledJob> Jobs { get; set; } 
}

public class ScheduledJob
{
    public string Job { get; set; }
    public string From { get; set; }
    public string To { get; set; }
}

public enum Gender
{
    Unknown = 0,
    Male = 1,
    Female = 2
}

 

請注意SaveUser這個action的參數,一個比較復雜的實體類的對象。DefaultModelBinder會自動將這個復雜的表單解析出來。這個保存的action將參數user直接序列化JSON字符串返回到瀏覽器。

 

下面看看HTML和JS。

 

HTML:

 1 <form id="formUserEditor" action="/demo/saveuser" method="POST">
 2     <table class="form">
 3         <colgroup>
 4             <col width="100"/>
 5             <col width="auto"/>
 6         </colgroup>
 7         <tbody>
 8             <tr>
 9                 <td>用戶名:</td>
10                 <td>
11                     <input id="txtUsername" type="text" name="username" />
12                 </td>
13             </tr>
14             <tr>
15                 <td>Email:</td>
16                 <td>
17                     <input id="txtEmail" type="text" name="email" />
18                 </td>
19             </tr>
20             <tr>
21                 <td>語言:</td>
22                 <td>
23                     <select id="ddlLanguages" name="language">
24                         <option value="zh-cn">中文</option>
25                         <option value="en-us">英文</option>
26                     </select>
27                 </td>
28             </tr>
29             <tr>
30                 <td>性別:</td>
31                 <td id="genders">
32                     <input type="radio" name="gender" value="@(Taoad.Web.Publics.Controllers.Gender.Unknown)" id="rdUnknown" />
33                     <label for="rdUnknown">未知</label>
34                     
35                     <input type="radio" name="gender" value="@(Taoad.Web.Publics.Controllers.Gender.Male)" id="rdMale" />
36                     <label for="rdMale"></label>
37                     
38                     <input type="radio" name="gender" value="@(Taoad.Web.Publics.Controllers.Gender.Female)" id="rdFemale" />
39                     <label for="rdFemale"></label>
40                 </td>
41             </tr>
42             <tr>
43                 <td>角色:</td>
44                 <td id="roles">
45                     <input type="checkbox" name="roleids" value="1" id="cb1" />
46                     <label for="cb1">管理員</label>
47                     
48                     <input type="checkbox" name="roleids" value="2" id="cb2" />
49                     <label for="cb2">部門經理</label>
50                     
51                     <input type="checkbox" name="roleids" value="3" id="cb3" />
52                     <label for="cb3">客戶</label>
53                 </td>
54             </tr>
55             <tr>
56                 <td>時間:</td>
57                 <td>
58                     <ul id="jobs">
59                         
60                     </ul>
61                     <input type="button" value="添加" id="btnAddJob"/>
62                 </td>
63             </tr>
64             <tr>
65                 <td></td>
66                 <td>
67                     <input type="button" value="保存" id="btnSave"/>
68                     <input type="button" value="取消" id="btnCancel" />
69                 </td>
70             </tr>
71         </tbody>
72     </table>
73 </form>
74 <hr/>
75 <div id="json">
76     
77 </div>

 

JS:

 1 <script language="javascript" type="text/javascript">
 2     $(document).ready(function () {
 3         $("#btnAddJob").click(function() {
 4             var $newLi = $(html);
 5             $("#jobs").append($newLi);
 6             bindLi($newLi);
 7         });
 8 
 9         $("#btnSave").click(function() {
10             var data = $("#formUserEditor").serialize();
11             $("#jobs li").each(function(i) {
12                 var prefix = "&jobs[" + i + "]";
13                 data += prefix + ".job=" + $(this).find(".job-id").val();
14                 data += prefix + ".from=" + $(this).find(".job-from").val();
15                 data += prefix + ".to=" + $(this).find(".job-to").val();
16             });
17             demo.ajax.post("/demo/saveuser", data, function(json) {
18                 $("#json").html(json);
19             });
20         });
21     });
22 
23     function bindLi(li) {
24         $(li).find(".btn-add").click(function () {
25             var $li = $(this).closest("li");
26             var $newLi = $(html);
27             $li.after($newLi);
28             bindLi($newLi);
29         });
30         $(li).find(".btn-delete").click(function () {
31             $(this).closest("li").remove();
32         });
33     }
34 
35     var html = '<li>\
36                     <select class="job-id">\
37                         <option value="job1">工作1</option>\
38                         <option value="job2">工作2</option>\
39                     </select>\
40                     <input type="text" placeholder="開始時間"  class="job-from"/>\
41                     ————\
42                     <input type="text" placeholder="結束時間"  class="job-to"/>\
43                     <a href="javascript:void(0);" class="btn-add">添加</a> |\
44                     <a href="javascript:void(0);" class="btn-delete">刪除</a>\
45                 </li>';
46 </script>

 

如果是如下的表單數據:

 

點擊保存之后,返回的JSON數據為:

 

可以看到所有的表單數據都保存成功了。

 

再看看request信息:

 

請注意content-type的值。

 

實際上,POST到服務器的表單數據只是一個字符串,如下:

 

復制出來就是下面這樣的字符串:

 ajax=true&username=leo&email=leo%40gmail.com&language=zh-cn&gender=Unknown&roleids=1&roleids=3&jobs[0].job=job1&jobs[0].from=9:00&jobs[0].to=10:00&jobs[1].job=job2&jobs[1].from=10:00&jobs[1].to=11:00 

 

由此可知,可用JS來拼接字符串,將整個表單通過鍵值對的形式序列化成一個字符串,再將該字符串傳到服務器,這時DefaultModelBinder就可以自動解析實體類了。

 

關鍵點在於,對於List或者數組類型的數據,要加上數組下標。這樣,任意復雜的數據結構,DefaultModelBinder都可以自動解析了。

 

思考一:

如果表單數據的鍵帶有”demouser”的前綴,如下所示,那么這個action的參數還能自動解析嗎?

 Demouser.username=leo&demouser.email=leo@gmail.com&demouser.jobs[0].job=job1&..... 

 

Action如下:

 1 [HttpPost]
 2 public string SaveUser(DemoUser user)
 3 {
 4     var result = string.Empty;
 5     if (user != null)
 6     {
 7         result = Serializer.ToJson(user);
 8     }
 9     return result;
10 }

 

如果action參數名稱又改成demouser呢?

 

思考二:

如果將action的參數名稱改成如下代碼所示,那么是否可以自動解析?(表單數據不帶”demouser”前綴)

 ajax=true&username=leo&email=leo%40gmail.com&language=zh-cn&gender=Unknown&roleids=1&roleids=3&jobs[0].job=job1&jobs[0].from=9:00&jobs[0].to=10:00&jobs[1].job=job2&jobs[1].from=10:00&jobs[1].to=11:00 

 

Action如下:

 1 [HttpPost]
 2 public string SaveUser(DemoUser demoUser)
 3 {
 4     var result = string.Empty;
 5     if (demoUser != null)
 6     {
 7         result = Serializer.ToJson(demoUser);
 8     }
 9     return result;
10 }

 

思考三:

如果action的參數是用另一個類包起來了,如下代碼所示,那么表單數據應該是怎么樣的字符串才能使DefaultModelBinder可以自動解析?

 1 public class UserEditorViewModel
 2 {
 3     public DemoUser DemoUser { get; set; }
 4 }
 5 
 6 [HttpPost]
 7 public string SaveUser(UserEditorViewModel model)
 8 {
 9     var result = string.Empty;
10     if (model != null)
11     {
12         result = Serializer.ToJson(model);
13     }
14     return result;
15 }

 

思考四:

如果action是這樣定義的,那么表單數據的字符串又該怎么拼?

 1 [HttpPost]
 2 public string SaveUser(DemoUser demoUser, List<ScheduledJob> scheduledJobs)
 3 {
 4     var result = string.Empty;
 5     if (demoUser != null)
 6     {
 7         demoUser.Jobs = scheduledJobs;
 8         result = Serializer.ToJson(demoUser);
 9     }
10     return result;
11 }

 

歡迎討論。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM