ASP.NET MVC——模型绑定

这篇文章我们来讲讲模型绑定(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 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控制器。

 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";
}

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

理解模型绑定

模型绑定是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.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 属性的类型,它可以是其他类型,只要该类型中含有Country和 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 属性绑定值。

时间: 2024-12-18 13:23:50

ASP.NET MVC——模型绑定的相关文章

[转] ASP.NET MVC 模型绑定的功能和问题

摘要:本文将与你深入探究 ASP.NET MVC 模型绑定子系统的核心部分,展示模型绑定框架的每一层并提供扩展模型绑定逻辑以满足应用程序需求的各种方法. 同时,你还会看到一些经常被忽视的模型绑定技术,并了解如何避免一些最常见的模型绑定错误. ASP.NET MVC 模型绑定通过引入自动填充控制器操作参数的抽象层.处理通常与使用 ASP.NET 请求数据有关的普通属性映射和类型转换代码来简化控制器操作. 虽然模型绑定看起来很简单,但实际上是一个相对较复杂的框架,由许多共同创建和填充控制器操作所需对

ASP.NET没有魔法——ASP.NET MVC 模型绑定解析(上篇)

前面文章介绍了ASP.NET MVC中的模型绑定和验证功能,本着ASP.NET MVC没有魔法的精神,本章内容将从代码的角度对ASP.NET MVC如何完成模型的绑定和验证进行分析,已了解其原理. 本文的主要内容有: ● ModelBinder ● ValuePrivoder ● ModelMetadata ● 简单模型与复杂模型 ● 小结 ModelBinder ModelBinder是ASP. NET MVC用于模型绑定的核心组件,所有的ModelBinder都实现了IModelBinder

asp.net mvc 模型绑定太糙淡了

之前就偶尔遇到模型绑定失效的问题,一直怪自己技术渣渣 不懂人家 而已.最近又遇到 自定义类 绑定失败,看了大牛scot文档 也不得姐..&……**……&*……*…………*%%(此处一堆脏话) 干脆自己直接丰庄个扩展方法,解析request 反序列.效果倍儿好!再也不担心模型绑定失效了,参数我想怎么传就怎么穿,顺带避免了微软时间/date*****/ 的大坑 哇哈哈哈.---------------------既然别人提供的封装方法那么难使 为嘛不自己造个? 大不了一样糙蛋呗 oh yeah

ASP.NET MVC Model绑定(一)

ASP.NET MVC Model绑定(一) 前言 ModelMetadata系列的结束了,从本篇开始就进入Model绑定部分了,这个系列阅读过后你会对Model绑定有个比较清楚的了解, 本篇对于Model绑定器的最基础的应用作个简单的示例展示,目的在于让大家事先了解一下Model绑定器是什么样的便于后续篇幅的理解. Model绑定 IModelBinder.自定义Model绑定器简单实现 Model绑定器在MVC框架中的位置 MVC中的默认Model绑定器生成过程 IModelBinderPr

ASP.NET MVC Model绑定(三)

ASP.NET MVC Model绑定(三) 前言 看过前两篇的朋友想必对Model绑定有个大概的了解,然而MVC框架给我们提供了更高的可扩展性的提供程序编程模式,也就是本篇的主题了,会讲解一下Model绑定器提供程序的实现以及解决一下上篇遗留的问题. 第一个问题是ModelBinderProviderCollection类型的执行过程? 还有个本篇的问题就是同样的向系统上下文中注册Model绑定器和Model绑定器提供程序,哪一个优先级更高? Model绑定 IModelBinder.自定义M

ASP.NET 的模型绑定(ModelBinding)

ModelBinding :用浏览器以HTTP请求方式发生数据来创建.NET对象的过程. 一.理解模型绑定. 1.模型绑定器是由IModelBinder接口定义的.下面是此接口的定义 namespace System.Web.Mvc { public interface IModelBinder { object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext); } } 2.在一

本地化ASP.NET核心模型绑定错误消息

默认错误消息: MissingBindRequiredValueAccessor A value for the '{0}' property was not provided. MissingKeyOrValueAccessor A value is required. ValueMustNotBeNullAccessor The value '{0}' is invalid. AttemptedValueIsInvalidAccessor The value '{0}' is not val

ASP.NET MVC Model绑定(二)

ASP.NET MVC Model绑定(二) 前言 上篇对于Model绑定的简单演示想必大家对Model绑定的使用方式有一点的了解,那大家有没有想过Model绑定器是在什么时候执行的?又或是执行的过程是什么样的?将在本篇为大家解除这些疑惑,在其中涉及到的一些描述类型和上下文参数会在后续的篇幅中讲到. Model绑定 IModelBinder.自定义Model绑定器简单实现 Model绑定器在MVC框架中的位置 MVC中的默认Model绑定器生成过程 IModelBinderProvider的简单

ASP.NET MVC Model绑定(六)

ASP.NET MVC Model绑定(六) 前言 前面的篇幅对于IValueProvider的使用做个基础的示例讲解,但是没并没有对 IValueProvider类型的实现做详细的介绍,然而MVC框架中给我们提供了几种默认的实现类型,在本篇中将会对NameValueCollectionValueProvider类型做一个示例讲解,了解一下MVC框架给我们提供的值提供程序是怎么处理Model值的. Model绑定 IModelBinder.自定义Model绑定器简单实现 Model绑定器在MVC