zoukankan      html  css  js  c++  java
  • 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类型的使用后面篇幅会有说明。


    作者:金源

  • 相关阅读:
    pat03-树1. 二分法求多项式单根(20)
    pat05-图1. List Components (25)
    pat06-图4. Saving James Bond
    pat05-图3. 六度空间 (30)
    pat05-图2. Saving James Bond
    pat04-树9. Path in a Heap (25)
    pat04-树8. Complete Binary Search Tree (30)
    pat04-树7. Search in a Binary Search Tree (25)
    pat04-树5. File Transfer (25)
    Two Sum
  • 原文地址:https://www.cnblogs.com/lcchuguo/p/5360147.html
Copyright © 2011-2022 走看看