前面的几个篇幅把Model部分的知识点划分红一个个的模块来说解,而在控制器执行过程当中分为好多个过程,对于控制器执行过程(一)主要讲解了过滤器以及在后面的过滤器篇幅中也有讲到,而在过滤器之中还有一些执行过程,也就是在受权过滤器执行完毕后,行为过滤器执行以前,咱们要作的就是Model绑定,面前也都说了以前对Model的知识点模块都讲解的差很少了,今天这个篇幅咱们就来看一下这些零散知识点的源头,也就是Model绑定的入口点。数组
HttpActionBinding的由来框架
咱们经过前面几篇的了解都知道在ASP.NET Web API框架中进入整个Model绑定的入口点就是在HttpActionBinding类型中,对于这个类型前面的篇幅也介绍过,它里面封装了ParameterBinding数组,这些ParameterBinding就是控制器方法中每一个参数执行Model绑定的对象了,既然咱们知道HttpActionBinding类型中有着许多ParameterBinding类型的对象实例,那么咱们就要看看HttpActionBinding类型是怎么生成的。less
示例代码1-1this
this.SetSingle<IActionValueBinder>(new DefaultActionValueBinder());
首先咱们看到示例代码1-1中能够看到在HttpConfiguration类型的服务容器中,默认注册为IActionValueBinder类型服务的是DefaultActionValueBinder类型。spa
示例代码1-2设计
namespace System.Web.Http.ModelBinding { public class DefaultActionValueBinder : IActionValueBinder { public DefaultActionValueBinder(); public virtual HttpActionBinding GetBinding(HttpActionDescriptor actionDescriptor); protected virtual HttpParameterBinding GetParameterBinding(HttpParameterDescriptor parameter); } }
代码1-2中所示的是DefaultActionValueBinder类型的定义,其中的这两个方法很重要,第一个GetBinding()方法是用以框架内部来进行调用,根据HttpActionDescriptor控制器方法描述类型对象获取到咱们所需的HttpActionBinding,而其内部实现则是调用下面的GetParameterBinding()方法,利用HttpActionDescriptor对象获取到HttpParameterDescriptor集合后,而后遍历的去调用GetParameterBinding()方法,从而可以获取到HttpParameterBinding对象实例,最后生成HttpActionBinding对象实例,从设计角度来看这个DefaultActionValueBinder类型中的两个方法GetBinding()和GetParameterBinding()方法都是采用了template method模式,这种模式在框架设计中很常见。3d
HttpParameterBinding的由来code
下面咱们就要来讲说GetParameterBinding()方法的细节实现了由于关乎着使用哪一种方式来进行绑定。也就是根据HttpParameterDescriptor类型实例怎么去建立HttpParameterBinding的。orm
示例代码1-3对象
protected virtual HttpParameterBinding GetParameterBinding(HttpParameterDescriptor parameter) { ParameterBindingAttribute parameterBinderAttribute = parameter.ParameterBinderAttribute; if (parameterBinderAttribute == null) { ParameterBindingRulesCollection parameterBindingRules = parameter.Configuration.ParameterBindingRules; if (parameterBindingRules != null) { HttpParameterBinding binding = parameterBindingRules.LookupBinding(parameter); if (binding != null) { return binding; } } Type parameterType = parameter.ParameterType; if (TypeHelper.IsSimpleUnderlyingType(parameterType) || TypeHelper.HasStringConverter(parameterType)) { return parameter.BindWithAttribute(new FromUriAttribute()); } parameterBinderAttribute = new FromBodyAttribute(); } return parameterBinderAttribute.GetBinding(parameter); }
代码1-3就是具体的实现了,那咱们就就来看一下其中的过程以及会涉及到的类型。
首先会根据参数HttpParameterDescriptor类型实例获取到在这个控制器方法参数上使用了ParameterBindingAttribute标识,而且获取ParameterBindingAttribute类型实例。咱们暂且就来看一下ParameterBindingAttribute类型定义。
示例代码1-4
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Class, Inherited = true, AllowMultiple = false)] public abstract class ParameterBindingAttribute : Attribute { // Methods protected ParameterBindingAttribute(); public abstract HttpParameterBinding GetBinding(HttpParameterDescriptor parameter); }
从代码1-4能够看出,这个ParameterBindingAttribute类型适用于类型以及参数,也就是说咱们选择绑定的方式能够在Model类型定义的时候标识这个特性,也能够在定义控制器方法的时候适当的给参数这个特性标识。
然而在这个类型中为何会有GetBinding()方法呢?由于这个类型是抽象类型,也就是采用了上面所说过的template method模式,而在子类实现中,根据自身适应的状况生成响应的HttpParameterBinding类型。看下以下的图表示相关的对象模型。
图1
上面图1中涉及到的每一个类型你们能够去看前面的篇幅,篇幅中有遗漏的就麻烦你们本身多动一下手去看看吧。
HttpParameterBinding的选择机制
接着代码1-3的思绪,在咱们获取到了ParameterBindingAttribute以后,并不知道这个控制器方法中的参数是否标识有ParameterBindingAttribute,或者是参数类型上是否有标识。这个时候假使是有的话,能够看到代码1-3中的最后一句代码,直接使用获取到的ParameterBindingAttribute类型进行调用GetBinding()方法,也就是在上一小节中图1所示的那样。
然而还有一种状况,就是咱们在定义控制器方法的时候参数没有明确的标识咱们要使用某种绑定机制,或者是在定义Model的时候没有明确的表示,这个时候框架则会从定义好的规则集合中根据当前控制其方法参数的描述类型来获取对应的ParameterBinding类型实例。以下的示例代码定义了规则集合的定义。
示例代码1-5
internal static ParameterBindingRulesCollection GetDefaultParameterBinders() { ParameterBindingRulesCollection ruless = new ParameterBindingRulesCollection(); ruless.Add(typeof(CancellationToken), parameter => new CancellationTokenParameterBinding(parameter)); ruless.Add(typeof(HttpRequestMessage), parameter => new HttpRequestParameterBinding(parameter)); ruless.Add(delegate (HttpParameterDescriptor parameter) { if (!typeof(HttpContent).IsAssignableFrom(parameter.ParameterType)) { return null; } return parameter.BindAsError(Error.Format(SRResources.ParameterBindingIllegalType, new object[] { parameter.ParameterType.Name, parameter.ParameterName })); }); return ruless; }
代码1-5中所表示的就是规则定义,意思就是在咱们使用HttpParameterDescriptor类型实例来从集合中想获取ParameterBinding的时候,ParameterBindingRulesCollection类型会把咱们的HttpParameterDescriptor类型实例中的ParameterType取出来和以前定义的每一项规则的类型进行比对,类型吻合了就会随之调用对应的委托类型进行ParameterBinding生成。从代码1-5中咱们能够看到的是规则中只有CancellationToken类型和HttpRequestMessage类型,假使这个时候咱们的控制其方法参数类型是自定义的复杂类型,这里也都没有定义,这个时候框架会取出HttpParameterDescriptor类型中的ParameterType进行判断,假使是能够转换成string类型的简单类型参数,则会生成一个FromUriAttribute类型做为标识,FromUriAttribute类型继承自ModelBinderAttribute类型。
假使这里的判断没有经过则说明是复杂类型,最后咱们再看待代码1-3中的定义最后生成的是FromBodyAttribute标识类型,这个时候请参照图1。
做者:金源
出处:http://www.cnblogs.com/jin-yuan/
本文版权归做者和博客园共有,欢迎转载,但未经做者赞成必须保留此段声明,且在文章页面