ASP.NET MVC Model绑定(四)

简介:

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
protected  virtual  object  GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor)
         {
             Type parameterType = parameterDescriptor.ParameterType;
             IModelBinder modelBinder =  this .GetModelBinder(parameterDescriptor);
             IValueProvider valueProvider = controllerContext.Controller.ValueProvider;
             string  str = parameterDescriptor.BindingInfo.Prefix ?? parameterDescriptor.ParameterName;
             Predicate< string > propertyFilter = GetPropertyFilter(parameterDescriptor);
             ModelBindingContext context2 =  new  ModelBindingContext
             {
                 FallbackToEmptyPrefix = parameterDescriptor.BindingInfo.Prefix ==  null ,
                 ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType( null , parameterType),
                 ModelName = str,
                 ModelState = controllerContext.Controller.ViewData.ModelState,
                 PropertyFilter = propertyFilter,
                 ValueProvider = valueProvider
             };
             ModelBindingContext bindingContext = 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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public  class  ModelBindingContext
     {
         public  ModelBindingContext();
         public  ModelBindingContext(ModelBindingContext bindingContext);
         public  bool  FallbackToEmptyPrefix {  get set ; }
         public  object  Model {  get set ; }
         public  ModelMetadata ModelMetadata {  get set ; }
         public  string  ModelName {  get set ; }
         public  ModelStateDictionary ModelState {  get set ; }
         public  Type ModelType {  get set ; }
         public  Predicate< string > PropertyFilter {  get set ; }
         public  IDictionary< string , ModelMetadata> PropertyMetadata {  get ; }
         //
         // 摘要:
         //     获取或设置值提供程序。
         //
         // 返回结果:
         //     值提供程序。
         public  IValueProvider ValueProvider {  get set ; }
     }

这里我们只需初步的了解ModelBindingContext类型就行了,回到主题中,上面说到从当前控制器对象的引用中直接获取的,那我们就去看一下控制器中的ValueProvider属性。我们就来看一下Controller类型,代码1-3.

代码1-3

1
2
3
4
public  abstract  class  Controller : ControllerBase, IActionFilter, IAuthorizationFilter, IDisposable, IExceptionFilter, IResultFilter
{
    ……
}

跟大家开了个玩笑,缓解下气氛。Controller类型中并没有我们所要找的属性,有的朋友想到了,对的是在基类类型中的,确实是在ControllerBase类型中的(代码1-4)。

代码1-4

1
2
3
4
5
public  abstract  class  ControllerBase : IController
{
    ……
    public  IValueProvider ValueProvider {  get set ; }
}

难道我们在使用IValueProvider的时候是要赋值到控制器对象上的吗?

当然不是了,我们看一下代码1-4中ValueProvider属性的实现,示例代码1-5.

代码1-5

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public  IValueProvider ValueProvider
         {
             get
             {
                 if  ( this ._valueProvider ==  null )
                 {
                     this ._valueProvider = ValueProviderFactories.Factories.GetValueProvider( this .ControllerContext);
                 }
                 return  this ._valueProvider;
             }
             set
             {
                 this ._valueProvider = value;
             }
         }

看到这里想必大家就应该已经了解了IValueProvider类型的由来了,是从系统的ValueProviderFactories类型的Factories属性中来根据当前控制器上下文获取到的。

这里我们看一下生成IValueProvider类型的几个相关类型的定义,示例代码1-6。

代码1-6

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
     public  static  class  ValueProviderFactories
     {
         // 摘要:
         //     获取应用程序的值提供程序工厂的集合。
         //
         // 返回结果:
         //     值提供程序工厂对象的集合。
         public  static  ValueProviderFactoryCollection Factories {  get ; }
     }
 
     public  class  ValueProviderFactoryCollection : Collection<ValueProviderFactory>
     {
         public  ValueProviderFactoryCollection();
         public  ValueProviderFactoryCollection(IList<ValueProviderFactory> list);
 
         // 摘要:
         //     为指定控制器上下文返回值提供程序工厂。
         //
         // 参数:
         //   controllerContext:
         //     一个对象,该对象封装有关当前 HTTP 请求的信息。
         //
         // 返回结果:
         //     用于指定控制器上下文的值提供程序工厂对象。
         public  IValueProvider GetValueProvider(ControllerContext controllerContext);
         protected  override  void  InsertItem( int  index, ValueProviderFactory item);
         protected  override  void  SetItem( int  index, ValueProviderFactory item);
     }
 
     public  abstract  class  ValueProviderFactory
     {
        
         protected  ValueProviderFactory();
 
         // 摘要:
         //     为指定控制器上下文返回值提供程序对象。
         //
         // 参数:
         //   controllerContext:
         //     一个对象,该对象封装有关当前 HTTP 请求的信息。
         //
         // 返回结果:
         //     值提供程序对象。
         public  abstract  IValueProvider GetValueProvider(ControllerContext controllerContext);
     }

ValueProviderFactories类型的这种模式前面见过太多了,就不说了,它里面包含着ValueProviderFactoryCollection类型的静态属性,而ValueProviderFactoryCollection类型又是ValueProviderFactory类型的集合类型,所以在最终生成IValueProvider类型的时候也是先遍历ValueProviderFactoryCollection类型,获取每个ValueProviderFactory类型的实例并且来生成IValueProvider类型,这里也是最先匹配而不是最优匹配。

这里捎带一句,可以用控制器上下文对象来对ValueProviderFactory类型中的生成逻辑进行分类,针对不同的控制器生成不同的IValueProvider类型。对于IValueProvider类型的使用后面篇幅会有说明。



     本文转自jinyuan0829 51CTO博客,原文链接:http://blog.51cto.com/jinyuan/1433305,如需转载请自行联系原作者





相关文章
|
2月前
|
开发框架 前端开发 .NET
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
118 0
|
2月前
|
开发框架 前端开发 JavaScript
JavaScript云LIS系统源码ASP.NET CORE 3.1 MVC + SQLserver + Redis医院实验室信息系统源码 医院云LIS系统源码
实验室信息系统(Laboratory Information System,缩写LIS)是一类用来处理实验室过程信息的软件,云LIS系统围绕临床,云LIS系统将与云HIS系统建立起高度的业务整合,以体现“以病人为中心”的设计理念,优化就诊流程,方便患者就医。
47 0
|
2月前
|
开发框架 前端开发 .NET
C# .NET面试系列六:ASP.NET MVC
<h2>ASP.NET MVC #### 1. MVC 中的 TempData\ViewBag\ViewData 区别? 在ASP.NET MVC中,TempData、ViewBag 和 ViewData 都是用于在控制器和视图之间传递数据的机制,但它们有一些区别。 <b>TempData:</b> 1、生命周期 ```c# TempData 的生命周期是短暂的,数据只在当前请求和下一次请求之间有效。一旦数据被读取,它就会被标记为已读,下一次请求时就会被清除。 ``` 2、用途 ```c# 主要用于在两个动作之间传递数据,例如在一个动作中设置 TempData,然后在重定向到另
184 5
|
2月前
|
开发框架 前端开发 .NET
进入ASP .net mvc的世界
进入ASP .net mvc的世界
|
2月前
|
JSON 前端开发 Java
开发必备技能:探索Spring MVC请求映射和参数绑定的奇妙之旅!
开发必备技能:探索Spring MVC请求映射和参数绑定的奇妙之旅!
|
8月前
|
开发框架 自然语言处理 前端开发
基于ASP.NET MVC开发的、开源的个人博客系统
基于ASP.NET MVC开发的、开源的个人博客系统
64 0
|
JavaScript 前端开发 .NET