ASP.NET MVC Model綁定(四)

ASP.NET MVC Model綁定(四)

前言

前面的篇幅對於Model綁定器IModelBinder以及實現類型、Model綁定器提供程序都做了粗略的講解,能夠把Model綁定器想象成一個大的容器,爲何這麼說呢?留個疑問在這裏。框架

首先控制器的方法參數多是不少種類型的、多是多個同一種類型的,應對這種狀況MVC框架使用的綁定實現都是IValueProvider來作的,而針對參數類型的不一樣等等一些狀況,IValueProvider的實現類型也是有很大的差別的,這些具體實現的講解會在後續的篇幅中講解。ide

都說旁觀者清,咱們不要走進MVC框架,站在外面看。本篇會已站在外面的角度去對IValueProvider作個描述。this

 

Model綁定

  • IModelBinder、自定義Model綁定器簡單實現
  • Model綁定器在MVC框架中的位置
  • MVC中的默認Model綁定器生成過程
  • IModelBinderProvider的簡單應用
  • IValueProvider在MVC框架中生成的位置以及過程
  • IValueProvider的應用場景
  • IValueProvider的實現之NameValueCollectionValueProvider

 

IValueProvider在MVC框架中生成的位置以及過程

生成的位置spa

你們能否記得在ASP.NET MVC Model綁定(二)中對於Model綁定器生成位置的描述,這裏借用一下那副描述生成位置的示意圖,code

圖1對象

圖1中所示,藍色線條執行流程中,在Model綁定器生成後,即會生成IValueProvider類型,說是生成有點不妥,改爲獲取吧。爲何這樣說在下面的生成部分會講到blog

 

生成的過程ip

咱們先看一下圖1中藍色線條流程的實現代碼。get

代碼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/

本文版權歸做者和博客園共有,歡迎轉載,但未經做者贊成必須保留此段聲明,且在文章頁面

相關文章
相關標籤/搜索