ASP.NET MVC5学习笔记之Action参数模型绑定基本过程
当我们在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参数模型绑定基本过程的更多相关文章
- ASP.NET MVC5学习笔记之Action参数模型绑定之模型元数据和元数据提供
一. 元数据描述类型ModelMetadata 模型元数据是对Model的描述信息,在ASP.NET MVC框架中有非常重要的作用,在模型绑定,模型验证,模型呈现等许多地方都有它的身影.描述Model ...
- ASP.NET MVC5学习笔记之Action参数模型绑定值提供体系
这一节我们关注模型绑定的值提供体系,先来介绍几个重要的接口 一. IValueProvider,接口定义如下: public interface IValueProvider { bool Conta ...
- ASP.NET MVC5学习笔记01
由于之前在项目中也使用MVC进行开发,但是具体是那个版本就不是很清楚了,但是我觉得大体的思想是相同的,只是版本高的在版本低的基础上增加了一些更加方便操作的东西.下面是我学习ASP.NET MVC5高级 ...
- ASP.NET MVC5学习笔记之Filter提供体系
前面我们介绍了Filter的基本使用,但各种Filter要在合适的时机运行起来,需要预先准备好,现在看看ASP.NET MVC框架是怎么做的. 一.Filter集合 在ControlerActionI ...
- ASP.NET MVC5学习笔记之Controller同步执行架构分析
在开始之前,声明一下,由于ASP.NET MVC5正式发布了,后面的分析将基于ASP.NET MVC5最新的源代码.在前面的内容我们分析了怎样根据路由信息来确定Controller的类型,并最终生成C ...
- ASP.NET MVC5 学习笔记-1 控制器、路由、返回类型、选择器、过滤器
[TOC] 1. Action 1.1 新建项目 新建项目->Web->Asp.net Web应用程序,选择MVC,选择添加测试. 在解决方案上右键,选择"管理NuGet程序包& ...
- ASP.NET MVC5学习笔记之Filter基本介绍
Filter是ASP.NET MVC框架提供的基于AOP(面向方面)设计,提供在Action执行前后做一些非业务逻辑通用处理,如用户验证,缓存等.现在来看看Filter相关的一些类型信息. 一.基本类 ...
- ASP.NET MVC5 学习笔记-2 Razor
1. Razor @*注释*@ 你在用 @Request.Browser.Browser, 发送邮件给support@qq.com, 转义@@qq @{ var amounts = new List& ...
- ASP.NET MVC5 学习笔记-3 Model
1. Model 1.1 添加一个模型 注意,添加属性时可以输入"prop",会自动输入代码段. public class CheckoutAccount { public int ...
随机推荐
- cocos2d-x 在xcode IOS模拟器中 开启IOS多点触控
在初始化代码中,开启当前层接受触摸 this->setTouchEnabled(true); 在AppController.mm文件中,设置开启多点触控 在- (BOOL)application ...
- iOS中FMDB的使用【单例】
DYDB.h Objective-C 12345678910111213141516 #import <Foundation/Foundation.h> #import <FMDB/ ...
- 查看用户的SQL执行历史
程序开发少不来SQL,基本都是基于SQL开发,程序仅仅起一个流程控制的作用.但是数据库本身存在许多内置的视图或者内置的表,如果打算研究SQL执行的效率已经SQL执行的历史记录,通过这些视图可以知道. ...
- MemoryStream 的GetBuffer() 和 ToArray()的区别
GetBuffer(): Note that the buffer contains allocated bytes which might be unused. For example, if th ...
- ExtJS 4.2 中自定义事件
前台HTML: <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www ...
- 用imageNamed加载图片产生的问题
通常我们会用imageNamed:来加载图片,但是用这个API有个问题,就是它会缓存加载的image. 因此,对于那些被重用的图片,这个API很高效.但是对于那些使用很少的图片,用这个就很耗内存,那怎 ...
- iOS中常见的设计模式——单例模式\委托模式\观察者模式\MVC模式
一.单例模式 1. 什么是单例模式? 在iOS应用的生命周期中,某个类只有一个实例. 2. 单例模式解决了什么问题? 想象一下,如果我们要读取文件配置信息,那么每次要读取,我们就要创建一个文件实例,然 ...
- .net重启iis线程池和iis站点程序代码【转】
转:http://www.jb51.net/article/44162.htm 重启站点: 复制代码代码如下: /// <summary> /// 根据名字重启站点.(没重 ...
- Facebook三种分享方式
一.去Facebook开发者中心注册APP,获取APP ID https://developers.facebook.com 二.导入 FBSDKCoreKit.Framework, FBSDKLog ...
- IE SEESION共享的问题
前几天,我们在开发工作流的过程中出现了一个比较奇怪的问题,原本看不到流程的人员,在登陆后却能够看到对应流程的待办任务,并且导致流程流向混乱!在调模式下调试程序发现(假设登陆两个用户)第二个登陆用户的信 ...