本文参考:http://www.cnblogs.com/willick/p/3424188.html

1、Model Binding是Http请求和Action方法之间的桥梁,是MVC框架根据Http请求创建.NET对象的过程。它根据Action方法中的Model对象的类型创建,NET对象,并将Http请求数据经过转换赋给该对象。

2、Model Binding是从路由引擎接收和处理Http请求后开始的。例如:

public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
} //1、当请求/Home/Index/1时,路由系统把最后一个片段1赋值给id变量。
//2、Action Invoker通过路由信息得知当前请求需要Index这个Action来处理;
//3、Action Invoker通过Model Binder(模型绑定器)来创建调用Action方法需要的数据对象;
//4、最后Action Invoker将数据对象赋值给Index这个Action的参数,再调用这个Action完成Http请求。

3、Model Binder实现了下列接口:

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

在MVC中可以有多个Model Binder,每个Binder都负责一种或多种类型的Model。当Action Invoker调用Action方法时,它先看这个Action方法需要的参数,然后为每个参数找到和参数类型对应的Model Binder,然后调用Model Binder的BindModel方法,BindModel方法再根据Action方法的参数名称从路由信息中获取参数值,最后把值提供给Action Invoker,由Action Invoker方法完成Action方法的调用。

4、Model Binder可以形象的理解为把数据绑定到一个Model的工具。当Action Invoker没有找到自定义的Model Binder时,就使用系统默认的DefaultModelBinder,它通过以下顺序查找要绑定到Model的值,一旦找到就停止查找:

  • Request.Form,HTML form 元素提供的值。
  • RouteData.Values,通过应用程序路由提供的值。
  • Request.QueryString,所请求 URL 的 query string 值。
  • Request.Files,客户端上传的文件

对于简单类型,DefaultModelBinder会通过System.ComponentModel命名空间下的TypeDescriptor类将其转换为和参数类型相同的类型。若转换失败则不会把值绑定到参数上。

    Tips:对于值类型,尽量使用可空类型或可选参数,以免报错。

5、对于复合类型(指不能被TypeConverter转换的类型),DefaultModelBinder类通过反射获取该类型所有的公开属性,然后依次进行绑定。

6、如果某个Action方法的参数的类型是某个对象的属性的类型,此时需要使用BindAttribute来告诉DefaultModelBinder只查找特定前缀的的名称:

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

需要注意的是使用 Bind 特性指定了前缀后,需要提交的表单元素的 name 属性必须有该前缀才能被绑定。

Bind 特性还有两个属性,Exclude 和 Include。它们可以指定在 Mdoel 的属性中,Binder 不查找或只查找某个属性,即在查找时要么只包含这个属性要么不包含这个属性。

7、Model Binder 把请求提交的数据绑定到数组和集合模型上有非常好的支持。

8、当 action 方法定义了参数时,Model Binding 的过程是自动的。我们也可以通过在Action方法中调用UpdateModel方法来对Model Binding的过程进行手动控制。示例:

public ActionResult Address()
{
IList<Address> addresses = new List<Address>();
UpdateModel(addresses, new FormValueProvider(ControllerContext));
return View(addresses);
}

示例指定只从Request.Form中查找数据。

9、FormValueProvider实现了IValueProvier接口,是ValueProvider的一种。RouteData.Values、Request.QueryString 和 Request.Files 的 Value Provider 分别是 RouteDataValueProviderQueryStringValueProviderHttpFileCollectionValueProvider

10、还有一种限制Model Binder数据来源的方法,示例:

//用 Action 方法的某个集合类型的参数来指定并存储从某一个来源获取的数据,这个集合类型(示例的 FormCollection) 也是 IValueProvider 接口的一个实现。
public ActionResult Address(FormCollection formData)
{
IList<Address> addresses = new List<Address>();
UpdateModel(addresses, formData);
return View(addresses);
}

11、有时候用户会提交一些 和 model 对象的属性不匹配的数据,如不合法的日期格式或给数值类型提供文本值,这时候绑定会出现错误,Model Binder 会用 InvalidOperationException 来表示。可以通过 Controller.ModelState 属性找到具体的错误信息,然后反馈给用户:

public ActionResult Address(FormCollection formData)
{
IList<Address> addresses = new List<Address>();
try
{
UpdateModel(addresses, formData);
}
catch (InvalidOperationException ex)
{
var allErrors = ModelState.Values.SelectMany(v => v.Errors);
// do something with allErrors and provide feedback to user
}
return View(addresses);
}

12、可以用 ModelState.IsValid 属性来检查提交的数据是否合法。

13、自定义ValueProvider示例:

//1、实现IValueProvier接口
public class CountryValueProvider : IValueProvider
{
public bool ContainsPrefix(string prefix)
{
return prefix.ToLower().IndexOf("country") > -;
} public ValueProviderResult GetValue(string key)
{
if (ContainsPrefix(key))
return new ValueProviderResult("China", "China", CultureInfo.InvariantCulture);
else
return null;
}
} //2、自定义ValueProviderFactory来实例化自定义的ValueProvider
public class CustomValueProviderFactory : ValueProviderFactory
{
public override IValueProvider GetValueProvider(ControllerContext controllerContext)
{
return new CountryValueProvider();
}
} //3、在Global类的Applcation_Start方法中进行注册
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
//通过 ValueProviderFactories.Factories 静态集合的 Insert 方法注册了我们的 CustomValueProviderFactory 类。
//Insert 方法中的 0 参数保证 Binder 将首先使用自定义的类来提供值。
//如果我们想在其他 value provider 不能提供值的时候使用,那么我们可以使用 Add 方法:ValueProviderFactories.Factories.Add(new CustomValueProviderFactory());
ValueProviderFactories.Factories.Insert(0, new CustomValueProviderFactory());
}

14、自定义Model Binder示例:

//1、实现IModelBinder接口
public class AddressBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
Address model = (Address)bindingContext.Model ?? new Address();
model.City = GetValue(bindingContext, "City");
model.Country = GetValue(bindingContext, "Country");
return model;
} private string GetValue(ModelBindingContext context, string name)
{
name = (context.ModelName == "" ? "" : context.ModelName + ".") + name;
ValueProviderResult result = context.ValueProvider.GetValue(name);
if (result == null || result.AttemptedValue == "")
return "<Not Specified>";
else
return (string)result.AttemptedValue;
}
} //2、注册
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
ModelBinders.Binders.Add(typeof(Address), new AddressBinder());
}

【ASP.NET MVC 学习笔记】- 16 Model Binding(模型绑定)的更多相关文章

  1. ASP.NET MVC 学习笔记-2.Razor语法 ASP.NET MVC 学习笔记-1.ASP.NET MVC 基础 反射的具体应用 策略模式的具体应用 责任链模式的具体应用 ServiceStack.Redis订阅发布服务的调用 C#读取XML文件的基类实现

    ASP.NET MVC 学习笔记-2.Razor语法   1.         表达式 表达式必须跟在“@”符号之后, 2.         代码块 代码块必须位于“@{}”中,并且每行代码必须以“: ...

  2. ASP.NET MVC 学习笔记-7.自定义配置信息 ASP.NET MVC 学习笔记-6.异步控制器 ASP.NET MVC 学习笔记-5.Controller与View的数据传递 ASP.NET MVC 学习笔记-4.ASP.NET MVC中Ajax的应用 ASP.NET MVC 学习笔记-3.面向对象设计原则

    ASP.NET MVC 学习笔记-7.自定义配置信息   ASP.NET程序中的web.config文件中,在appSettings这个配置节中能够保存一些配置,比如, 1 <appSettin ...

  3. ASP.NET MVC学习笔记-----Filter2

    ASP.NET MVC学习笔记-----Filter(2) 接上篇ASP.NET MVC学习笔记-----Filter(1) Action Filter Action Filter可以基于任何目的使用 ...

  4. ASP.NET MVC学习笔记-----Filter

    ASP.NET MVC学习笔记-----Filter(1) Filter类型 接口 MVC的默认实现 Description Authorization IAuthorizationFilter Au ...

  5. ASP.NET MVC学习笔记-----Filter(2)

    接上篇ASP.NET MVC学习笔记-----Filter(1) Action Filter Action Filter可以基于任何目的使用,它需要实现IActionFilter接口: public ...

  6. ASP.NET Core 2 学习笔记(九)模型绑定

    ASP.NET Core MVC的Model Binding会将HTTP Request数据,以映射的方式对应到参数中.基本上跟ASP.NET MVC差不多,但能Binding的来源更多了一些.本篇将 ...

  7. ASP.NET MVC 学习笔记(1)

    从头开始系统地学习ASP.NET MVC 为什么要学习ASP.NET MVC?原因很多,可以先来看一下最早的ASP.NET WebForm的一些缺点: 传说中面试经常要问到的ASP.NET WebFo ...

  8. 【.NET-MVC】ASP.NET MVC学习笔记1-概述

    第 1 篇:理解控制器和视图 MVC概述 MVC原理就是模型.视图.控制器的框架.   (其实也是种思想,为了让前端.程序.数据分开,也是想实现低耦合.高内聚) MVC请求流程是:访问控制器,控制器来 ...

  9. ASP.NET MVC学习笔记 第三天

    布局: 如果不使用布局页,需要将Layout属性设置为null. @{     Layout = null; } 使用默认布局页: 使用Add View对话框,选择使用布局页(是布局页的名称文本框为空 ...

随机推荐

  1. 201521123013 《Java程序设计》第10周学习总结

    1. 本章学习总结 2. 书面作业 Q1.finally题目4-2 1.1 截图你的提交结果(出现学号) 1.2 4-2中finally中捕获异常需要注意什么? finally块中的异常必须在fina ...

  2. 201521123050 《Java程序设计》第9周学习总结

    1. 本周学习总结 2. 书面作业 本次PTA作业题集异常 1.常用异常 题目5-1 1.1 截图你的提交结果(出现学号) 1.2 自己以前编写的代码中经常出现什么异常.需要捕获吗(为什么)?应如何避 ...

  3. Eclipse rap 富客户端开发总结(11) : rcp/rap与spring ibatis集成

    1. rcp/rap 与 spring 集成 Activator 是rcp/rap 启动时需要加载的类, 只需要加载一遍,所以与spring 集成的时候一般是在这个类里面加载spring 的Appli ...

  4. Jquery第二篇【选择器、DOM相关API、事件API】

    前言 前面已经介绍过了Jquery这门语言,其实就是一个javaScript的库-能够简化我们书写的代码-.本博文主要讲解使用Jquery定位HTML控件[定位控件就是获取HTML的标签],使用Jqu ...

  5. mysql、mariadb安装和多实例配置

    本文目录:1. mysql单实例安装 1.1 rpm安装mysql 1.2 通用二进制包安装mysql 1.2.1 初始化数据库 1.2.2 安装后的规范化操作 1.3 编译安装 1.3.1 编译安装 ...

  6. Android方法数不能超过65535

    为什么方法数不能超过65535?搬上Dalvik工程师在SF上的回答,因为在Dalvik指令集里,调用方法的invoke-kind指令中,method reference index只给了16bits ...

  7. java学习——java按值传递和按址传递

    先复制一个面试/笔试的题: 当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递? 答案: 是值传递.Java语言的方法调用只支持参 ...

  8. Java的基本程序设计结构【2】

    注释 与大多数程序设计语言一样,Java 中的注释也不会出现在可执行程序中.因此,可以在源程序中根据需要添加任意多的注释,而不必担心可执行代码会膨胀.在Java 中,有三种书写注释的方式. 最常用的方 ...

  9. LDA工程实践之算法篇之(一)算法实现正确性验证(转)

    研究生二年级实习(2010年5月)开始,一直跟着王益(yiwang)和靳志辉(rickjin)学习LDA,包括对算法的理解.并行化和应用等等.毕业后进入了腾讯公司,也一直在从事相关工作,后边还在yiw ...

  10. Python网络编程socket练习(TCP)

    服务器端:server.py # -*- coding: utf-8 -*- from socket import * HOST='' PORT=5000 BUFF_SIZE=1024 ADDR=(H ...