ASP.NET MVC——模型綁定

   這篇文章咱們來說講模型綁定(Model Binding),其實在初步瞭解ASP.NET MVC以後,你們可能都會產生一個疑問,爲何URL片斷最後會轉換爲例如int型或者其餘類型的參數呢?這裏就不得不說模型綁定了。模型綁定是指,用瀏覽器以HTTP請求方式發送的數據來建立.NET對象的過程。每當定義具備參數的動做方法時,一直是在依賴着這種模型綁定過程。html

準備項目瀏覽器

    咱們先來建立一個MVC項目,名叫MVCModels,並在Models文件夾中建立一個新的類文件Person。併發

 1 using System;
 2 
 3 namespace MVCModels.Models
 4 {
 5     public class Person
 6     {
 7         public int PersonId { get; set; }
 8         public string FirstName { get; set; }
 9         public string LastName { get; set; }
10         public DateTime BirthDate { get; set; }
11         public Address HomeAddress { get; set; }
12         public Role Role { get; set; }
13     }
14 
15     public class Address
16     {
17         public string Line { get; set; }
18         public string City { get; set; }
19         public string PostalCode { get; set; }
20         public string Country { get; set; }
21     }
22 
23     public enum Role
24     {
25         Admin,
26         User,
27         Guest
28     }
29 }

    另外定義一個Home控制器。app

 1 using MVCModels.Models;
 2 using System.Linq;
 3 using System.Web.Mvc;
 4 
 5 namespace MVCModels.Controllers
 6 {
 7     public class HomeController : Controller
 8     {
 9         private Person[] personDate = {
10             new Person { PersonId = 1, FirstName = "Adam", LastName = "Freeman", Role = Role.Admin },
11             new Person { PersonId = 2, FirstName = "Jacqui", LastName = "Griffyth", Role = Role.User },
12             new Person { PersonId = 1, FirstName = "John", LastName = "Smith", Role = Role.Guest },
13         };
14         public ActionResult Index(int id)
15         {
16             Person dataItem = personDate.Where(p => p.PersonId == id).First();
17             return View(dataItem);
18         }
19     }
20 }

    接下來再建立一個視圖文件Index。ui

@model MVCModels.Models.Person
@{
    ViewBag.Title = "Index";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>Person</h2>
<div>
    <label>ID:</label>
    @Html.DisplayFor(m => m.PersonId)
</div>
<div>
    <label>First Name:</label>
    @Html.DisplayFor(m => m.FirstName)
</div>
<div>
    <label>Last Name:</label>
    @Html.DisplayFor(m => m.LastName)
</div>
<div>
    <label>Role:</label>
    @Html.DisplayFor(m => m.Role)
</div>

理解模型綁定spa

    模型綁定是HTTP請求與C#方法之間的一個橋樑,它根據 Action 方法中的 Model 類型建立 .NET 對象,並將 HTTP 請求數據通過轉換賦給該對象。當咱們啓動項目,並導航到/Home/Index/1,咱們會看見圖下:code

    當咱們請求 /Home/Index/1 URL 時,路由系統便將最後一個片斷值 1 賦給了 id 變量。action invoker 經過路由信息知道當前的請求須要 Index action 方法來處理,但它調用 Index action 方法以前必須先拿到該方法參數的值。 默認的動做調用器ControllerActionInvoker,要依靠模型綁定器來生成調用動做所須要的的數據對象,模型綁定器由IModelBinder接口所定義。在本例中,動做調用器會檢查Index方法,並發現它具備一個int型參數,因而會查找負責int值綁定的綁定器,並調用它的BindModel方法。orm

使用默認模型綁定器htm

    雖然應用程序能夠自定義模型綁定器,可是大多數狀況下仍是依靠內建的綁定器類DefaultModelBinder。當動做調用器找不到綁定某個類型的自定義綁定器時,就會使用這個默認的模型綁定器,默認狀況下,這個模型綁定器會搜索四個位置。以下表所示:對象

DefaultModelBinder類查找參數數據的順序
描述
Request.From 由用戶在HTML的表單元素中提供值
RouteData.Values 用應用程序路由得到的值
Request.QueryString 包含在請求URL中的查詢字符串部分的數據
Request.Files 請求中上傳的文件

    這些位置將被依次搜索,在本例中,DefaultModelBinder會爲id參數查找如下的一個值:

    1.Request.Form["id"]

    2.RouteData.Values["id"]

    3.Request.QueryString["id"]

    4.Request.Files["id"]

綁定簡單類型

    處理簡單參數類型時,DefaultModelBinder會使用System.ComponentModel.TypeDescriptor類,講請求數據得到的字符參數值轉換爲參數類型,若是沒法轉換,那麼DefaultModelBinder便不能綁定到Model。好比訪問/Home/Index/apple,便會出現如圖所示:

    默認模型綁定器看到須要的是int值,若是視圖將URL中提供的apple值轉換爲int型,就會出錯,此時咱們能夠修改代碼,爲參數提供一個默認值,這樣當默認綁定器沒法轉換時也不會出錯了。

1 ...  
2 public ActionResult Index(int id = 1)
3 {
4     Person dataItem = personDate.Where(p => p.PersonId == id).First();
5     return View(dataItem);
6 }

綁定複雜類型

     當動做方法參數是符合類型時(即不能用TypeConverter類進行轉換的屬性),DefaultModelBinder類將用反射類獲取public屬性集。好的,咱們如今來修改代碼。

 1 using MVCModels.Models;
 2 using System.Linq;
 3 using System.Web.Mvc;
 4 
 5 namespace MVCModels.Controllers
 6 {
 7     public class HomeController : Controller
 8     {
 9         private Person[] personDate = {
10             new Person { PersonId = 1, FirstName = "Adam", LastName = "Freeman", Role = Role.Admin },
11             new Person { PersonId = 2, FirstName = "Jacqui", LastName = "Griffyth", Role = Role.User },
12             new Person { PersonId = 1, FirstName = "John", LastName = "Smith", Role = Role.Guest },
13         };
14         public ActionResult Index(int id = 1)
15         {
16             Person dataItem = personDate.Where(p => p.PersonId == id).First();
17             return View(dataItem);
18         }
19         public ActionResult CreatePerson()
20         {
21             return View(new Person());
22         }
23         [HttpPost]
24         public ActionResult CreatePerson(Person model)
25         {
26             return View("Index", model);
27         }
28     }
29 }

    另外建立一個CreatePerson視圖。

 1 @model MVCModels.Models.Person
 2 @{
 3     ViewBag.Title = "CreatePerson";
 4     Layout = "~/Views/Shared/_Layout.cshtml";
 5 }
 6 
 7 <h2>CreatePerson</h2>
 8 @using (Html.BeginForm())
 9 {
10     <div>
11         <label>
12             @Html.LabelFor(m => m.PersonId)
13             @Html.EditorFor(m => m.PersonId)
14         </label>
15     </div>
16     <div>
17         <label>
18             @Html.LabelFor(m => m.FirstName)
19             @Html.EditorFor(m => m.FirstName)
20         </label>
21     </div>
22     <div>
23         <label>
24             @Html.LabelFor(m => m.LastName)
25             @Html.EditorFor(m => m.LastName)
26         </label>
27     </div>
28     <div>
29         <label>
30             @Html.LabelFor(m => m.Role)
31             @Html.EditorFor(m => m.Role)
32         </label>
33     </div>
34     <button type="submit">Submit</button>
35 }

    在表單回遞給CreatePerson方法時,默認綁定器發現動做方法須要一個Person對象,便會依次處理每一個屬性。綁定器會從請求中找到每個值。若是一個屬性須要另外一個複合類型時,那麼該過程會重複執行。例如本例中,Person類的HomeAddress屬性是Address類型,在爲Line屬性查找值時,模型綁定器查找的是HomeAddress.Line的值,即模型對象的屬性名(HomeAddress)與屬性類型(Address)的屬性名(Line)的組合。

Bind特性

    咱們還能夠用bind特性爲 Address 類型的參數綁定 Person 對象中的 HomeAddress 屬性值,例如這樣:

 

1 public ActionResult DisplayAddress([Bind(Prefix="HomeAddress")]Address address) 
2 {
3     return View(address);
4 }

 

    DisplayAddress action 方法的參數類型 Address 不必定必須是 Person 的 HomeAddress 屬性的類型,它能夠是其餘類型,只要該類型中含有City

或 Country 同名的屬性就都會被綁定到。不過,要注意的是,使用 Bind 特性指定了前綴後,須要提交的表單元素的 name 屬性必須有該前綴才能被綁定。Bind 特性還有兩個屬性,Exclude 和 Include。它們能夠指定在 Mdoel 的屬性中,Binder 不查找或只查找某個屬性,即在查找時要麼只包含這個屬性要麼不包含這個屬性。以下面的 action 方法:

1 public ActionResult DisplayAddress([Bind(Prefix = "HomeAddress", Exclude = "Country")]Address address) 
2 {
3     return View(address);
4 }

這時 Binder 在綁定時不會對 Address 這個 Model 的 Country 屬性綁定值。

相關文章
相關標籤/搜索