当我们在Controller中定义一个Action,通常会定义一个或多个参数,每个参数称为一个模型,ASP.NET MVC框架提供了一种机制称为模型绑定,会尝试自动从请求的信息中实例化每一个模型并赋值。这其中又涉及模型的元数据提供和模型的验证。

  我们不妨试想一下,如果来定义一种从字符串值到对象值的映射机制,可能要知道以下信息:

1. 对象的类型和名称等对象本身的元数据

2. 对象属性的元数据信息

3. 查询字符串到对象和对象属性的值映射机制

4. 具体的绑定过程

  前面的1,2 由ASP.NET MVC框架的元数据提供机制保证,3由其值提供机制保证,4由具体的模型绑定对象执行。只不过ASP.NET MVC在做完模型绑定后,顺带验证了模型的验证。

  现在我们来看看具体的代码.参数模型绑定执行肯定在具体的Action方法执行之前,在ControllerActionInvoker的InvokeAction方中,执行Action方法是InvokeActionMethodWithFilters,在其前一行代码是IDictionary<string, object> parameters = GetParameterValues(controllerContext, actionDescriptor); 这个方法的目的把Action的所有参数值根据参数名封装到一个字典里。现在来看看其实现:

 protected virtual IDictionary<string, object> GetParameterValues(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
{
Dictionary<string, object> parametersDict = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
ParameterDescriptor[] parameterDescriptors = actionDescriptor.GetParameters(); foreach (ParameterDescriptor parameterDescriptor in parameterDescriptors)
{
parametersDict[parameterDescriptor.ParameterName] = GetParameterValue(controllerContext, parameterDescriptor);
}
return parametersDict;
}

可以看到通过ActionDescriptor获取所有的参数描述信息数组,每个参数通过调用GetParameterValue获取其参数值。这里有一个重要的类ParameterDescriptor,该类是个抽象类其定义如下:

  public abstract class ParameterDescriptor : ICustomAttributeProvider
{ protected ParameterDescriptor();
public abstract ActionDescriptor ActionDescriptor { get; } public virtual ParameterBindingInfo BindingInfo { get; } public virtual object DefaultValue { get; }
public abstract string ParameterName { get; }
public abstract Type ParameterType { get; }
public virtual object[] GetCustomAttributes(bool inherit);
public virtual object[] GetCustomAttributes(Type attributeType, bool inherit);
public virtual bool IsDefined(Type attributeType, bool inherit);
}

这个类型除了BindingInfo属性其它属性没什么好说的,BindingInfo的类型是ParameterBindingInfo,描述该参数类型模型绑定过程中将使用的信息,具体那些信息我们来看这个类型的定义:

  public abstract class ParameterBindingInfo
{
protected ParameterBindingInfo();
public virtual IModelBinder Binder { get; }
public virtual ICollection<string> Exclude { get; }
public virtual ICollection<string> Include { get; }
public virtual string Prefix { get; }
}

Binder属性是指参数特定的绑定器,通过ModelBinderAttribute来指定, Exclude和Include表示不参与或参与参数属性模型绑定列表,Prefix 表示绑定过程中使用的前缀,这三个属性是通过BindAttribute属性来设置的。

 现在回过头来看看GetParameterValue 方法的实现:

 protected virtual object GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor)
{
// collect all of the necessary binding properties
Type parameterType = parameterDescriptor.ParameterType;
IModelBinder binder = GetModelBinder(parameterDescriptor);
IValueProvider valueProvider = controllerContext.Controller.ValueProvider;
string parameterName = parameterDescriptor.BindingInfo.Prefix ?? parameterDescriptor.ParameterName;
Predicate<string> propertyFilter = GetPropertyFilter(parameterDescriptor); // finally, call into the binder
ModelBindingContext bindingContext = new ModelBindingContext()
{
FallbackToEmptyPrefix = (parameterDescriptor.BindingInfo.Prefix == null), // only fall back if prefix not specified
ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, parameterType),
ModelName = parameterName,
ModelState = controllerContext.Controller.ViewData.ModelState,
PropertyFilter = propertyFilter,
ValueProvider = valueProvider
}; object result = binder.BindModel(controllerContext, bindingContext);
return result ?? parameterDescriptor.DefaultValue;
}

a. 前面的几行代码准备绑定上下文使用的信息,简单的这里不说了,具体的ModelBinder通过GetModelBinder方法获取,它的实现是这样的:

  return parameterDescriptor.BindingInfo.Binder ?? Binders.GetBinder(parameterDescriptor.ParameterType);

  我们可以知道,通过ModelBinderAttribute指定的ModelBinder具有最高的优先级,Binders是ModelBinders.Binders静态属性,如果参数未指定ModelBinder,则通过ModelBinders.Binders.ModelBinders.Binders.GetBinder方法查找,具体查找这里不分析了,这里给出一个结果:

  1. 在参数上应用了ModelBinderAttribute

  2. 在ModelBinderProvider集合中查找

  3. 在全局注册的模型绑定集合表中查找

  4. 在参数类型上通过CustomModelBinderAttribute指定的模型绑定类型

  5. 返回默认的DefaultModelBinder

 b. 实例化绑定上文下,我们看到如果我们通过BinderAttribute的Prefix指定了前缀,系统默认的FallbackToEmptyPrefix将不再使用, 另外参数模型的元数据通过调用系统的元数据提供机制ModelMetadataProviders.Current.GetMetadataForType.

c. 执行模型绑定,如果返回null再返回参数指定的默认值

这段代码信息量比较大,包含了元数据提供机制,值提供机制,模型绑定与验证。后面的章节将分别描述。

ASP.NET MVC5学习笔记之Action参数模型绑定基本过程的更多相关文章

  1. ASP.NET MVC5学习笔记之Action参数模型绑定之模型元数据和元数据提供

    一. 元数据描述类型ModelMetadata 模型元数据是对Model的描述信息,在ASP.NET MVC框架中有非常重要的作用,在模型绑定,模型验证,模型呈现等许多地方都有它的身影.描述Model ...

  2. ASP.NET MVC5学习笔记之Action参数模型绑定值提供体系

    这一节我们关注模型绑定的值提供体系,先来介绍几个重要的接口 一. IValueProvider,接口定义如下: public interface IValueProvider { bool Conta ...

  3. ASP.NET MVC5学习笔记01

    由于之前在项目中也使用MVC进行开发,但是具体是那个版本就不是很清楚了,但是我觉得大体的思想是相同的,只是版本高的在版本低的基础上增加了一些更加方便操作的东西.下面是我学习ASP.NET MVC5高级 ...

  4. ASP.NET MVC5学习笔记之Filter提供体系

    前面我们介绍了Filter的基本使用,但各种Filter要在合适的时机运行起来,需要预先准备好,现在看看ASP.NET MVC框架是怎么做的. 一.Filter集合 在ControlerActionI ...

  5. ASP.NET MVC5学习笔记之Controller同步执行架构分析

    在开始之前,声明一下,由于ASP.NET MVC5正式发布了,后面的分析将基于ASP.NET MVC5最新的源代码.在前面的内容我们分析了怎样根据路由信息来确定Controller的类型,并最终生成C ...

  6. ASP.NET MVC5 学习笔记-1 控制器、路由、返回类型、选择器、过滤器

    [TOC] 1. Action 1.1 新建项目 新建项目->Web->Asp.net Web应用程序,选择MVC,选择添加测试. 在解决方案上右键,选择"管理NuGet程序包& ...

  7. ASP.NET MVC5学习笔记之Filter基本介绍

    Filter是ASP.NET MVC框架提供的基于AOP(面向方面)设计,提供在Action执行前后做一些非业务逻辑通用处理,如用户验证,缓存等.现在来看看Filter相关的一些类型信息. 一.基本类 ...

  8. ASP.NET MVC5 学习笔记-2 Razor

    1. Razor @*注释*@ 你在用 @Request.Browser.Browser, 发送邮件给support@qq.com, 转义@@qq @{ var amounts = new List& ...

  9. ASP.NET MVC5 学习笔记-3 Model

    1. Model 1.1 添加一个模型 注意,添加属性时可以输入"prop",会自动输入代码段. public class CheckoutAccount { public int ...

随机推荐

  1. java爬虫实战

    1.下载jxl.jar包,网上多的是 2.编写如下代码: package com.beyond.url; import java.io.BufferedReader;import java.io.Fi ...

  2. Android双击Back退出应用

    前言 在app主界面点击back时,通常有以下几种方式进行退出 单击即退出 弹出确认Dialog 再次点击退出程序 个人最喜欢方式3,相比于方式2,不需要再把手指移动到屏幕中央点击Dialog,相比于 ...

  3. DZ!NT论坛 3.6.711删除用户各种错解决方案

    DZ!NT论坛 3.6.711删除用户各种错解决方案   首先删除一个用户~ado.net报错 对象名  'dnt_spaceposts' 无效. 对象名 'dnt_spaceconfigs' 无效. ...

  4. C# ToolStripProgressBar

    ToolStripProgressBar 将所有 ToolStrip控件的移动和渲染功能和其典型的进程跟踪功能结合在一起.ToolStripProgressBar通常放在StatusStrip中,偶尔 ...

  5. linux中如何查看进程占用了哪些端口?

    使用netstat –apn | grep <进程名>便可以查看指定进程所占用的端口.

  6. MCADEx Tools 6.3下载地址

    MCADEx Tools 6.3下载地址: http://pan.baidu.com/s/1pLxQPkR 修改参数批量设置工具为模型批量检查工具; 修改模型批量检查过滤工具; 修改工程图管理过滤工具 ...

  7. Java高级软件工程师面试考纲(转)

    如果要应聘高级开发工程师职务,仅仅懂得Java的基础知识是远远不够的,还必须懂得常用数据结构.算法.网络.操作系统等知识.因此本文不会讲解具体的技术,笔者综合自己应聘各大公司的经历,整理了一份大公司对 ...

  8. 超图(hypergraph)

    超图是什么? 超图的本质特征在于它的超边,它可以连接两个以上的结点(包括两个).按这样的意义来说,我们所熟悉的普通图只是超图的一个特例而已,而超图则定义了一个更加宽泛的图. 超图的数学定义为:对于超图 ...

  9. excel中单元格计算

    首先,得明确excel中相对引用和绝对引用的概念,这里$符号起着关键作用,当在一个行或列的指示符前面加$则表示绝对引用,否则相对引用,具体: 1.相对引用,复制公式时地址跟着发生变化,如C1单元格有公 ...

  10. CSS3 伪类选择器 :nth-child()

    :nth-child()可以选择某个的一个或多个特定的子元素,你可以按这种方式进行选择: :nth-child(length);/*参数是具体数字*/ :nth-child(n);/*参数是n,n从0 ...