ASP.NET MVC Model绑定(四)
前面的篇幅对于Model绑定器IModelBinder以及实现类型、Model绑定器提供程序都作了粗略的讲解,可以把Model绑定器想象成一个大的容器,为什么这么说呢?留个疑问在这里。
首先控制器的方法参数可能是很多种类型的、可能是多个同一种类型的,应对这种情况MVC框架使用的绑定实现都是IValueProvider来做的,而针对参数类型的不同等等一些情况,IValueProvider的实现类型也是有很大的差异的,这些具体实现的讲解会在后续的篇幅中讲解。
都说旁观者清,我们不要走进MVC框架,站在外面看。本篇会已站在外面的角度去对IValueProvider做个描述。
Model绑定IModelBinder、自定义Model绑定器简单实现
Model绑定器在MVC框架中的位置
MVC中的默认Model绑定器生成过程
IModelBinderProvider的简单应用
IValueProvider在MVC框架中生成的位置以及过程
IValueProvider的应用场景
IValueProvider的实现之NameValueCollectionValueProvider
IValueProvider在MVC框架中生成的位置以及过程生成的位置
大家可否记得在ASP.NET MVC Model绑定(二)中对于Model绑定器生成位置的描述,这里借用一下那副描述生成位置的示意图,
图1
图1中所示,蓝色线条执行流程中,在Model绑定器生成后,即会生成IValueProvider类型,说是生成有点不妥,改成获取吧。为什么这样说在下面的生成部分会讲到
生成的过程
我们先看一下图1中蓝色线条流程的实现代码。
代码1-1
protectedvirtualobjectGetParameterValue(ControllerContextcontrollerContext,ParameterDescriptorparameterDescriptor){TypeparameterType=parameterDescriptor.ParameterType;IModelBindermodelBinder=this.GetModelBinder(parameterDescriptor);IValueProvidervalueProvider=controllerContext.Controller.ValueProvider;stringstr=parameterDescriptor.BindingInfo.Prefix??parameterDescriptor.ParameterName;Predicate<string>propertyFilter=GetPropertyFilter(parameterDescriptor);ModelBindingContextcontext2=newModelBindingContext{FallbackToEmptyPrefix=parameterDescriptor.BindingInfo.Prefix==null,ModelMetadata=ModelMetadataProviders.Current.GetMetadataForType(null,parameterType),ModelName=str,ModelState=controllerContext.Controller.ViewData.ModelState,PropertyFilter=propertyFilter,ValueProvider=valueProvider};ModelBindingContextbindingContext=context2;return(modelBinder.BindModel(controllerContext,bindingContext)??parameterDescriptor.DefaultValue);}
对于代码1-1中所示的方法,不用去管的它的返回类型以及这个方法的作用,我们现在想知道的就是IValueProvider是怎么来的!!!
从代码1-1中,我们可以明确的看到在生成Model绑定器过后,MVC框架从ControllerContext控制器上下文参数对象中获得了当前请求所请求的控制器的引用,然后根据当前的控制器对象引用获取到IValueProvider类型。
然后MVC框架会实例化ModelBindingContext类型,并且把刚刚获取的IValueProvider类型赋值到其中的ValueProvider属性上。
对于ModelBindingContext类型,Model绑定上下文对象,看下它的定义代码1-2。
代码1-2
publicclassModelBindingContext{publicModelBindingContext();publicModelBindingContext(ModelBindingContextbindingContext);publicboolFallbackToEmptyPrefix{get;set;}publicobjectModel{get;set;}publicModelMetadataModelMetadata{get;set;}publicstringModelName{get;set;}publicModelStateDictionaryModelState{get;set;}publicTypeModelType{get;set;}publicPredicate<string>PropertyFilter{get;set;}publicIDictionary<string,ModelMetadata>PropertyMetadata{get;}////摘要://获取或设置值提供程序。////返回结果://值提供程序。publicIValueProviderValueProvider{get;set;}}
这里我们只需初步的了解ModelBindingContext类型就行了,回到主题中,上面说到从当前控制器对象的引用中直接获取的,那我们就去看一下控制器中的ValueProvider属性。我们就来看一下Controller类型,代码1-3.
代码1-3
publicabstractclassController:ControllerBase,IActionFilter,IAuthorizationFilter,IDisposable,IExceptionFilter,IResultFilter{……}
跟大家开了个玩笑,缓解下气氛。Controller类型中并没有我们所要找的属性,有的朋友想到了,对的是在基类类型中的,确实是在ControllerBase类型中的(代码1-4)。
代码1-4
publicabstractclassControllerBase:IController{……publicIValueProviderValueProvider{get;set;}}
难道我们在使用IValueProvider的时候是要赋值到控制器对象上的吗?
当然不是了,我们看一下代码1-4中ValueProvider属性的实现,示例代码1-5.
代码1-5
publicIValueProviderValueProvider{get{if(this._valueProvider==null){this._valueProvider=ValueProviderFactories.Factories.GetValueProvider(this.ControllerContext);}returnthis._valueProvider;}set{this._valueProvider=value;}}
看到这里想必大家就应该已经了解了IValueProvider类型的由来了,是从系统的ValueProviderFactories类型的Factories属性中来根据当前控制器上下文获取到的。
这里我们看一下生成IValueProvider类型的几个相关类型的定义,示例代码1-6。
代码1-6
publicstaticclassValueProviderFactories{//摘要://获取应用程序的值提供程序工厂的集合。////返回结果://值提供程序工厂对象的集合。publicstaticValueProviderFactoryCollectionFactories{get;}}publicclassValueProviderFactoryCollection:Collection<ValueProviderFactory>{publicValueProviderFactoryCollection();publicValueProviderFactoryCollection(IList<ValueProviderFactory>list);//摘要://为指定控制器上下文返回值提供程序工厂。////参数://controllerContext://一个对象,该对象封装有关当前HTTP请求的信息。////返回结果://用于指定控制器上下文的值提供程序工厂对象。publicIValueProviderGetValueProvider(ControllerContextcontrollerContext);protectedoverridevoidInsertItem(intindex,ValueProviderFactoryitem);protectedoverridevoidSetItem(intindex,ValueProviderFactoryitem);}publicabstractclassValueProviderFactory{protectedValueProviderFactory();//摘要://为指定控制器上下文返回值提供程序对象。////参数://controllerContext://一个对象,该对象封装有关当前HTTP请求的信息。////返回结果://值提供程序对象。publicabstractIValueProviderGetValueProvider(ControllerContextcontrollerContext);}
ValueProviderFactories类型的这种模式前面见过太多了,就不说了,它里面包含着ValueProviderFactoryCollection类型的静态属性,而ValueProviderFactoryCollection类型又是ValueProviderFactory类型的集合类型,所以在最终生成IValueProvider类型的时候也是先遍历ValueProviderFactoryCollection类型,获取每个ValueProviderFactory类型的实例并且来生成IValueProvider类型,这里也是最先匹配而不是最优匹配。
这里捎带一句,可以用控制器上下文对象来对ValueProviderFactory类型中的生成逻辑进行分类,针对不同的控制器生成不同的IValueProvider类型。对于IValueProvider类型的使用后面篇幅会有说明。
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。