您好,欢迎来到九壹网。
搜索
您的当前位置:首页ASP.NETMVC——模型绑定

ASP.NETMVC——模型绑定

来源:九壹网
ASP.NETMVC——模型绑定

这篇⽂章我们来讲讲模型绑定(Model Binding),其实在初步了解ASP.NET MVC之后,⼤家可能都会产⽣⼀个疑问,为什么URL⽚段最后会转换为例如int型或者其他类型的参数呢?这⾥就不得不说模型绑定了。模型绑定是指,⽤浏览器以HTTP请求⽅式发送的数据来创建.NET对象的过程。每当定义具有参数的动作⽅法时,⼀直是在依赖着这种模型绑定过程。

准备项⽬

我们先来创建⼀个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 Address16 {

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 Role24 {

25 Admin,26 User,27 Guest28 }29 }

另外定义⼀个Home控制器。

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。

@model MVCModels.Models.Person@{

ViewBag.Title = \"Index\";

Layout = \"~/Views/Shared/_Layout.cshtml\";}

Person

@Html.DisplayFor(m => m.PersonId)

@Html.DisplayFor(m => m.FirstName)

@Html.DisplayFor(m => m.LastName)

@Html.DisplayFor(m => m.Role)

理解模型绑定

模型绑定是HTTP请求与C#⽅法之间的⼀个桥梁,它根据 Action ⽅法中的 Model 类型创建 .NET 对象,并将 HTTP 请求数据经过转换赋给该对象。当我们启

动项⽬,并导航到/Home/Index/1,我们会看见图下:

当我们请求 /Home/Index/1 URL 时,路由系统便将最后⼀个⽚段值 1 赋给了 id 变量。action invoker 通过路由信息知道当前的请求需要 Index action ⽅法来

处理,但它调⽤ Index action ⽅法之前必须先拿到该⽅法参数的值。 默认的动作调⽤器ControllerActionInvoker,要依靠模型绑定器来⽣成调⽤动作所需要的的数据对象,模型绑定器由IModelBinder接⼝所定义。在本例中,动作调⽤器会检查Index⽅法,并发现它具有⼀个int型参数,于是会查找负责int值绑定的绑定器,并调⽤它的BindModel⽅法。

使⽤默认模型绑定器

虽然应⽤程序可以⾃定义模型绑定器,但是⼤多数情况下还是依靠内建的绑定器类DefaultModelBinder。当动作调⽤器找不到绑定某个类型的⾃定义绑定器

时,就会使⽤这个默认的模型绑定器,默认情况下,这个模型绑定器会搜索四个位置。如下表所⽰:

DefaultModelBinder类查找参数数据的顺序

Request.FromRouteData.ValuesRequest.QueryStringRequest.Files

描述

由⽤户在HTML的表单元素中提供值⽤应⽤程序路由获得的值

包含在请求URL中的查询字符串部分的数据请求中上传的⽂件

这些位置将被依次搜索,在本例中,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

CreatePerson

8 @using (Html.BeginForm()) 9 {

10

11

12 @Html.LabelFor(m => m.PersonId)13 @Html.EditorFor(m => m.PersonId)14 15

16

17

18 @Html.LabelFor(m => m.FirstName)19 @Html.EditorFor(m => m.FirstName)20 21

22

23

24 @Html.LabelFor(m => m.LastName)25 @Html.EditorFor(m => m.LastName)26 27

28

29

30 @Html.LabelFor(m => m.Role)31 @Html.EditorFor(m => m.Role)32 33

34 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\2 {

3 return View(address);4 }

这时 Binder 在绑定时不会对 Address 这个 Model 的 Country 属性绑定值。

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- 91gzw.com 版权所有 湘ICP备2023023988号-2

违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务