什么是Model Binder?
MVC可以将用户提交的数据绑定到Action参数,我们将这个过程称之为模型绑定,在模型绑定中有两个关键:一个是值提供器,用于确定数据来源,另一个称为模型绑定器,用于确定如何将值绑定到特性的数据模型。
Model Binder使用场景
处理HTTP request 请求中的数据据。
将客户端post中的数据,转化成Model,作为Action的对象参数(当数据在Request.Form, route data, or the URL query string中时,可用ModelBinder提供数据)
由图可以看出Model Binder主要作用是包装了Request.Form, route data, or the URL query string参数。
值提供器
值提供器是一组实现了IValueProvider接口的类,MVC中的值提供其使用了标准的抽象工厂设计模式。
类图
MVC提供了四种默认的值提供器
面向主要的几种数据来源:
FormValueProvider:表单数据,对应于ASP.NET的Request.Form集合
QueryStringValueProvider:查询字符串,对应于ASP.NET的Request.QueryString集合
HttpFileCollectionValueProvider:文件集合,数据来源于Request.Files集合
RouteDataValueProvider:路由信息,对应于RouteData.Values集合
第一个是自定义的一个值提供工厂;其余四个是就上面讲的默认值。
动态图
一个请求到来,大致处理流程如下:
控件器找到满足条件的ValueFactories;
每个ValueFactory 找到一个对应**ValueProvider(如FormValueProvider)
**ValueProvider 查找键值是否存在,如果存在就返回值。
MVC中默认的模型绑定器
模型绑定器用于将值提供器提供的数据映射到特定的模型类型:绑定器可以从值提供器中获取数据,并根据控制器方法参数类型,自动实例化参数并填充数据。
类图如下:
ModelBinder 图
上图说明:
ModelBinders是一个静态类,内部封装了ModelBinderDictionary(Binders属性),包含默认的绑定器列表。
MVC中实现四种模型绑定器:
HttpPostedFileBaseModelBinder:用于处理HttpPostedFileBase类型
ByteArrayModelBinder:用于处理Byte[]类型
LinqBinaryModelBinder:用于处理Linq中的Binary类型
DefaultModelBinder:默认绑定器,如果某个类型没有特定的绑定器,则使用此绑定器。(在DefaultBinder属性中)
ModelBinderDictionary是一个IModelBinder字典,键为类型,值为类型所对应的绑定器。
CustomModelBinderAttribute是一个用于指定自定义绑定器的特性的抽象基类,方法GetBinder用于返回一个绑定器实例。ModelBinderAttribute是CustomModelBinderAttribute的一个实现,它根据指定的绑定器类型,返回其实例。MVC在查找适当的绑定器时,遵循以下顺序:
在参数上通过ModelBinderAttribute特性指定的绑定器
在ModelBinders.Binders中注册的绑定器
在类型上通过ModelBinderAttribute特性指定的绑定器
默认绑定器(通常为DefaultModelBinder)
Default Model Binder
DefaultBinder属性指定如果集合中不存在指定类型的绑定器时,应返回的默认绑定器,默认为DefaultModelBinder。我们可以通过此属性来指定我们自己的默认绑定器。
(请结合上面的“ModelBinder 图”看)
BindAttribute特性用于指定默认绑定器在绑定时的具体行为:Exlude属性指定绑定器在填充数据时,不处理的属性列表,Include属性指定绑定器在填充数据时,只需处理的属性列表,Prefix用于指定类型的前缀,默认情况下,前缀为控制器方法中参数的名称。IsPropertyAllowed方法用于判断特定的属性是否需要被处理。
一个例子说明问题:
// 更新数据
UpdateModel(person, new[] { "FirstName" });
return View(person);
}
页面:
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
RequestForm
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Person</h2>
<p>
FirstName:<%= Model.FirstName %>
</p>
<p>
LastName:<%= Model.LastName %>
</p>
</asp:Content>
结果:
Person
FirstName:wt
LastName:wt
----------------------------------------------------------------------------------------------------------------------------------------------------
例子说明:当post数据时,Default Model Binder 会根据Person的属性名称,查找Request中对应的值--》生成实例传给方法 作为参数(person),参数类型也可以为简单类型;若在request中没有找着,则生成空的对象实例--->处理。(这就要求:提交input name 要和对象的属性名称相同)
----------------------------------------------------------------------------------------------------------------------------------------------------
注意:MVC中常规获取数据的方式
// TODO:1.Request.Form传参数,不利于测试,测试时需要往Request里面加内容
person.FirstName =Request.Form["FirstName"];
person.LastName = Request.Form["LastName"];
return View(person );
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult FormCollection(FormCollection formCollection)
{
Person person = new Person();
// TODO:2.利于测试,测试时需要可虚构FormCollection对象就行。
person.FirstName = formCollection["FirstName"];
person.LastName = formCollection["LastName"];
return View(person);
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Person(Person person)
{
// TODO:3.利于测试,测试时需要可虚构Person对象就行。
person.FirstName = person.FirstName + " Updated";
// 更新数据
UpdateModel(person, new[] { "FirstName" });
return View(person);
}