ASP.NET 的模型绑定(ModelBinding)

ModelBinding :用浏览器以HTTP请求方式发生数据来创建.NET对象的过程。



一、理解模型绑定。

1、模型绑定器是由IModelBinder接口定义的。下面是此接口的定义

namespace System.Web.Mvc
{
    public interface IModelBinder
    {
        object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext);
    }
}

2、在一个Mvc程序中,可以有多个模型绑定器,而每个绑定器可以负责一个或者多个模型类型。

3、模型绑定器负责生产动作方法的参数值,并把这个值传送给动作调用器,由动作调用器把这个值注入到目标的动作方法中去。

这通常意味着要对请求数据的某些元素进行转换,但是Mvc框架对如何获取这些数据并无如何的限制。

模型绑定的过程是通过模型绑定器来实现的,其目的是用请求中所包含的数据来创建对象。

下面是模型绑定的步骤:
(1)、检查要创建的对象的名称和类型。

(2)、通过对象名称查找请求,并找到可用数据。

(3)、根据对象类型将找到的数据值要转换的类型。

(4)、通过对象名称,对象类型,和经过处理的数据来构造目标对象。

(5)、将构造好的对象传送给动作调用器,并由动作调用器将对象注入到动作方法中。



二、ASP.Net 默认的模型绑定器(DefaultModelBinder)

1.一个应用程序可以包含多个模型绑定器,但大多数值依赖Mvc框架内置的绑定器类DefaultModelBinder。这个模型绑定器在默认情况下会按照顺序查找下面4个位置:

Request.Form,RouteData.Values,Request.QueryString,Request.Files. 这个4个地方,只要有一个地方找值,就回停止搜索。

2.当动作方法的参数为简单类型时,DefaultModelBinder会试图用System.ComponentModel.TypeDescriptor类把已经从请求数据中获取到的字符串值转换成类型的值。

3.当动作方法的参数为复杂类型时(就是不能用TypeConverter类进行转换的类型),DefaultModelBinder将用反射来获取public属性集合,如果依次进行绑定。如果还是复杂类型,将再次执行此过程,获取public属性集合,直到全部能绑定。不同的是这些属性的名称是嵌套的(HomeAddress.Line1)。

4、指定自定义前缀。在默认模型绑定器查找数据项是,可以为它指定要查找的自定义前缀。

public ActionResult Register(Person firstPerson,[Bind(Prefix=‘myPerson‘)]Person secondPerson)

5、有选择的绑定。我们可以利用Bind注解属性把模型属性包含到或排除到绑定过程。

只包含FirstName和LastName

public ActionResult Register([Bind(Include="FirstName,LastName")]Person person)

只排除IsApprove和Role

public ActionResult Register([Bind(Exclude="IsApproved,Role")]Person person)



三、绑定到XXX (DefaultModelBinder能处理具有相同名称的多个数据项的方法)

例如:

@{
    ViewBag.Title = "Address";

}
<h2>Addrss</h2>
@Html.TextBox("movies")
@Html.TextBox("movies")
@Html.TextBox("movies")<input type="submit" value="提交"/>

3个Html.TextBox铺助方法生产的3个input元素,它们都会以movies所谓其name标签属性的值:

<input id="movies" name="movies" type="text" value="" />
<input id="movies" name="movies" type="text" value="" />
<input id="movies" name="movies" type="text" value="" />
<input id="movies" name="movies" type="text" value="" />
<input id="movies" name="movies" type="text" value="" />
<input id="movies" name="movies" type="text" value="" />

<input type="submit" value="提交"/>

在一个动作方法中接受多个数据项:

[HttpPost]
public ActionResult Index(List<string> movies)
{
//...
}

1.绑定到自定义类型集合

什么是自定义类型:不属于.NET体系架构中的那些已知的类型。比如我所定义的如何类型都是自定义类型。

用集合对象中的索引号作为对象各属性名的前置来生成HTML。然后在动作方法中用自定义类型的集合作为参数就可以了。

只要确保适当的生成索引值,模型绑定器就能够查找并绑定到所定义的所有数据元素。

2.绑定到非序列化索引的集合

使用任意字符串键来定义集合的数据项。:只要定义一个名为“index”的隐藏input元素,以指定数据项目的键

<h4>First Person</h4>
<input type="hidden" name="index" value="firstPerson"/>
First Name:@Html.TextBox("[firstPerson].FirstName")
Last Name:@Html.TextBox("[FirstPerson].LastName")

<h4>Second Person</h4>
<input type="hidden" name="index" value="secondPerson"/>
First Name:@Html.TextBox("[secondPerson].FirstName")
Last Name:@Html.TextBox("[secondPerson].LastName")

该清单input元素的name添加了与隐藏的索引元素相匹配的前置([firstPerson],[secondPerson])。模型绑定器会检测这个索引,并在绑定过程中把它与数据值关联在一起。

3.绑定到字典

默认绑定器能够绑定到字典(Dictionary),但要遵循一种特殊的命名序列。

<h4>First Person</h4>
<input type="hidden" name="[0].key" value="firstPerson"/>
First Name:@Html.TextBox("[0].value.FirstName")
Last Name:@Html.TextBox("[0].value.LastName")

<h4>Second Person</h4>
<input type="hidden" name="[1].key" value="secondPerson"/>
First Name:@Html.TextBox("[1].value.FirstName")
Last Name:@Html.TextBox("[1].value.LastName")

当绑定到Dictionary<string,Person>或者IDictionary<string,Person>时,该字典将含有从属于firstPerson和secondPerson键的2个Person对象。可以用下面的动作方法来接受数据:

[HttpPost]

public ViewResult Register(IDictionary<string,Person>people){...}



四、手动调用模型绑定。

当给动作方法定义了参数,模型绑定过程是自动执行的。我们也可以手动的控制这个过程,这样我们能够更明确的控制如何实例化模型,从何处获取数据,以及如何处理数据解析错误等。

       [HttpPost]
        public ActionResult Index()
        {
            string name = "";
            UpdateModel(name);
            return View();
        }  

UpdateModel方法以上一条语句生成的模型对象为参数,并试图用标准的绑定过程来获取其值。

手动调用模型绑定的过程的原因之一是为了支持模型对象的依赖性注入(DI)。

       [HttpPost]
        public ActionResult Index()
        {
            //加入DI支持.但這不是加入DI支持的唯一方法
            Address addressor = (Address)DependencyResolver.Current.GetServices(typeof(Address));
            UpdateModel(addressor);
            return View();
        }

1、限定绑定到特定的数据源

通过给UpdateModel方法提供IValueProvider类型的对象来指定特定的数据来源。

        [HttpPost]
        public ActionResult Index()
        {
            //加入DI支持.但這不是加入DI支持的唯一方法
            Address addressor = (Address)DependencyResolver.Current.GetServices(typeof(Address));
            //限定address的值來自Request.Form中
            UpdateModel(addressor, new FormValueProvider(ControllerContext));
            return View();
        } 

4个默认的数据来源都有一个IValueProvider的实现。

数据源 IValueProvider实现
Request.Form FormValueProvider
RouteData.Values RouteDataValueProvider
Request.QueryString QueryStringValueProvider
Request.Files HttpFileCollectionValueProvider

限定数据源最普遍的方式是只查找表单值。我们可以用一个更加雅致的方法实现。而不必创建FormValueProvider类实例。

      [HttpPost]
        public ActionResult Index(FormCollection formData)
        {
            //加入DI支持.但這不是加入DI支持的唯一方法
            Address addressor = (Address)DependencyResolver.Current.GetServices(typeof(Address));
            //限定address的值來自Request.Form中
            UpdateModel(addressor,formData);
            return View();
        }

2.处理绑定错误。

用户难免会提供一些不能绑定到相应的模型属性的值。当我们明确调用模型绑定石,我们需要负责处理此类的如何错误。

模型绑定器是通过抛出InvalidOperationException异常来表示绑定错误。错误的细节通过ModelState特性来查看。

因此我们使用UpdateModel方法时,必须做好扑捉该异常的准备,并用ModelState把错误信息表示给用户。

//添加扑捉模型绑定过程中的异常代码 方法一    

[HttpPost]
        public ActionResult Index(FormCollection formData)
        {
            //加入DI支持.但這不是加入DI支持的唯一方法
            Address address = (Address)DependencyResolver.Current.GetServices(typeof(Address));

            try
            {
                //限定address的值來自Request.Form中
                UpdateModel(address, formData);
            }catch(InvalidOperationException er)
            {
                //基於ModelState提供用戶介面反饋
            }
            return View(address);
        }

另一个方法是使用TryUpdateModel方法。如果绑定成功就返回"True",不成功就返回"false".

//扑捉模型绑定过程的异常代码 方法二

[HttpPost]
        public ActionResult Index(FormCollection formData)
        {
            //加入DI支持.但這不是加入DI支持的唯一方法
            Address address = (Address)DependencyResolver.Current.GetServices(typeof(Address));

            //try
            //{
            //    //限定address的值來自Request.Form中
            //    UpdateModel(address, formData);
            //}catch(InvalidOperationException er)
            //{
            //    //基於ModelState提供用戶介面反饋
            //}

            if (TryUpdateModel(address, formData))
            {
                //正常處理
            }
            else
            {
                //基於ModelState提供用戶介面反饋
            }
            return View(address);
        }


五、使用模型绑定接收文件上传

对于接收文件上传,要做的全部工作是定义一个以HttpPotedFileBase类为参数类型的动作方法。模型绑定器会用与这个上传文件相应的数据来填充它。

ASP.NET 的模型绑定(ModelBinding)

时间: 2024-11-05 13:59:08

ASP.NET 的模型绑定(ModelBinding)的相关文章

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

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

本地化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 Binding),其实在初步了解ASP.NET MVC之后,大家可能都会产生一个疑问,为什么URL片段最后会转换为例如int型或者其他类型的参数呢?这里就不得不说模型绑定了.模型绑定是指,用浏览器以HTTP请求方式发送的数据来创建.NET对象的过程.每当定义具有参数的动作方法时,一直是在依赖着这种模型绑定过程. 准备项目 我们先来创建一个MVC项目,名叫MVCModels,并在Models文件夹中创建一个新的类文件Person. 1 using Syste

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 Core MVC/WebAPi 模型绑定探索

前言 相信一直关注我的园友都知道,我写的博文都没有特别枯燥理论性的东西,主要是当每开启一门新的技术之旅时,刚开始就直接去看底层实现原理,第一会感觉索然无味,第二也不明白到底为何要这样做,所以只有当你用到了,你再去看理论性的文章时才会豁然开朗,这是我一直以来学习技术的方法.本文我们来讲解.NET Core中的模型绑定. 话题 在ASP.NET Core之前MVC和Web APi被分开,也就说其请求管道是独立的,而在ASP.NET Core中,WebAPi和MVC的请求管道被合并在一起,当我们建立控

ASP.NET MVC 的自定义模型绑定

最近在研究 ASP.NET MVC 模型绑定,发现 DefaultModelBinder 有一个弊端,就是无法实现对浏览器请求参数的自定义,最初的想法是想为实体模型的属性设置特性(Attribute),然后通过取得设置的特性值对属性进行赋值,研究了好久 MVC 源码之后发现可以通过重写 DefaultModelBinder 的 BindProperty 方法可以达到预期的目的. ASP.NET MVC 中有一个自定义模型绑定特性 CustomModelBinderAttribute,打算通过重写

【转】ASP.NET Core MVC/WebAPi 模型绑定探索

前言 相信一直关注我的园友都知道,我写的博文都没有特别枯燥理论性的东西,主要是当每开启一门新的技术之旅时,刚开始就直接去看底层实现原理,第一会感觉索然无味,第二也不明白到底为何要这样做,所以只有当你用到了,你再去看理论性的文章时才会豁然开朗,这是我一直以来学习技术的方法.本文我们来讲解.NET Core中的模型绑定. 话题 在ASP.NET Core之前MVC和Web APi被分开,也就说其请求管道是独立的,而在ASP.NET Core中,WebAPi和MVC的请求管道被合并在一起,当我们建立控

Asp.Net MVC在过滤器中使用模型绑定

废话不多话,直接上代码 1.创建MVC项目,新建一个过滤器类以及使用到的实体类: 1 public class DemoFiltersAttribute : AuthorizeAttribute 2 { 3 public override void OnAuthorization(AuthorizationContext filterContext) 4 { 5 var person = new Person(); 6 //过滤器中使用模型绑定 7 BindModel<Person>(filt