• 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

    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

    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

    public abstract class Controller : ControllerBase, IActionFilter, IAuthorizationFilter, IDisposable, IExceptionFilter, IResultFilter
    {
       ……
    }

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

    代码1-4

    public abstract class ControllerBase : IController
    {
       ……
       public IValueProvider ValueProvider { get; set; }
    }

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

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

    代码1-5

    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

        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类型的使用后面篇幅会有说明。

     

    作者:金源

    出处:http://www.cnblogs.com/jin-yuan/

    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面

  • 相关阅读:
    Single Number II
    Pascal's Triangle
    Remove Duplicates from Sorted Array
    Populating Next Right Pointers in Each Node
    Minimum Depth of Binary Tree
    Unique Paths
    Sort Colors
    Swap Nodes in Pairs
    Merge Two Sorted Lists
    Climbing Stairs
  • 原文地址:https://www.cnblogs.com/jin-yuan/p/3819206.html
Copyright © 2020-2023  润新知