<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      ModelBinder——ASP.NET MVC Model綁定的核心

      Model的綁定體現(xiàn)在從當(dāng)前請求提取相應(yīng)的數(shù)據(jù)綁定到目標(biāo)Action方法的參數(shù)。通過前面的介紹我們知道Action方法的參數(shù)通過ParameterDescriptor來描述,ParameterDescriptor的BindingInfo屬性表示的ParameterBindingInfo對象具有一個名為ModelBinder的組件用于完成針對當(dāng)前參數(shù)的Model綁定。ModelBinder可以看成是整個Model綁定系統(tǒng)的核心,我們先來認(rèn)識這個重要的組件。[本文已經(jīng)同步到《How ASP.NET MVC Works?》中]

      目錄
      一、 ModelBinder
      二、CustomModelBinderAttribute與ModelBinderAttribute
      三、ModelBinders
      四、ModelBinderProvider

      一、 ModelBinder

      用于進(jìn)行Model綁定的ModelBinder對象實(shí)現(xiàn)了接口IModelBinder。如下面的代碼片斷所示,IModelBinder接口具有唯一的BindModel方法用于實(shí)現(xiàn)針對某個參數(shù)的綁定操作,該方法的返回值表示的就是最終作為參數(shù)值的對象。

         1: public interface IModelBinder
         2: {
         3:     object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext);
         4: }

      IModelBinder的BindModel方法接受兩個參數(shù),一個是表示當(dāng)前的Controller上下文,另一個是表示針對當(dāng)前Model綁定的上下文,通過類型ModelBindingContext表示。在Controller初始化的時候,Controller上下文已經(jīng)被創(chuàng)建出來,所以我們只要能夠針對當(dāng)前的Model綁定創(chuàng)建相應(yīng)的ModelBindingContext,我們就能使用基于某個參數(shù)的ModelBinder得到對應(yīng)的參數(shù)值。關(guān)于ModelBindingContext的創(chuàng)建我們會在后續(xù)部分進(jìn)行的單獨(dú)介紹,我們先來介紹一下ModelBinder的提供機(jī)制。

      二、CustomModelBinderAttribute與ModelBinderAttribute

      如果針對某個參數(shù)的ParameterDescriptor具有相應(yīng)的ModelBinder,那么它會被優(yōu)先選擇用于針對該參數(shù)的Model綁定,那么ParameterDescriptor的ModelBinder是如何來提供的呢?這是實(shí)際上設(shè)置一個具有如下定義的CustomModelBinderAttribute特性。抽象類CustomModelBinderAttribute定義了唯一的抽象方法GetBinder用于獲取相應(yīng)的ModelBinder對象。

         1: [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Interface | AttributeTargets.Enum | AttributeTargets.Struct 
         2:     | AttributeTargets.Class, AllowMultiple=false, Inherited=false)]
         3: public abstract class CustomModelBinderAttribute : Attribute
         4: {
         5:     public abstract IModelBinder GetBinder();
         6: }

      在ASP.NET MVC應(yīng)用編程接口中,CustomModelBinderAttribute具有一個具有如下定義的唯一繼承類型ModelBinderAttribute。我們可以通過應(yīng)用ModelBinderAttribute特性動態(tài)地選擇用于Model綁定的ModelBinder類型。

         1: [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Interface | 
         2:     AttributeTargets.Enum | AttributeTargets.Struct | AttributeTargets.Class, 
         3:     AllowMultiple=false, Inherited=false)]
         4: public sealed class ModelBinderAttribute : CustomModelBinderAttribute
         5: {   
         6:     public ModelBinderAttribute(Type binderType);
         7:     public override IModelBinder GetBinder();
         8:  
         9:     public Type BinderType { [CompilerGenerated] get;  }
        10: }

      從應(yīng)用在ModelBinderAttribute類型上的AttributeUsageAttribute定義可以看出該特性不僅僅可以應(yīng)用在參數(shù)上,也可以應(yīng)用類型(接口、枚舉、結(jié)構(gòu)和類)上,這意味我們既可以將它應(yīng)用在Action方法的某個參數(shù)上,也可以將它應(yīng)用在某個參數(shù)的類型上。但是ParameterDescriptor只會解析應(yīng)用在參數(shù)上的特性,所以應(yīng)用在參數(shù)對象類型上的ModelBinderAttribute對它是無效的。

      為了演示ModelBinderAttribute特性對ParameterDescriptor的影響,我們來進(jìn)行一個簡單的實(shí)例演示。在一個通過Visual Studio的ASP.NET MVC項(xiàng)目模板創(chuàng)建的空Web應(yīng)用中定義了如下幾個類型,其中FooModelBinder和BarModelBinder是顯現(xiàn)了IModelBinder的自定義ModelBinder類型,而Foo、Bar和Baz是三個將被作為Action方法參數(shù)的數(shù)據(jù)類型,其中Bar上應(yīng)用了ModelBinderAttribute特性并將ModelBinder類型設(shè)置為BarModelBinder。

         1: public class FooModelBinder : IModelBinder
         2: {
         3:     public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
         4:     {
         5:         throw new NotImplementedException();
         6:     }
         7: }
         8: public class BarModelBinder : IModelBinder
         9: {
        10:     public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        11:     {
        12:         throw new NotImplementedException();
        13:     }
        14: }
        15:  
        16: public class Foo { }
        17: [ModelBinder(typeof(BarModelBinder))]
        18: public class Bar { }
        19: public class Baz { }

      然后再創(chuàng)建的默認(rèn)HomeController中定義如下兩個Action方法。DoSomething方法具有三個參數(shù),類型分別是Foo、Bar和Baz,在第一個參數(shù)上應(yīng)用了ModelBinderAttribute特性并將ModelBinder類型設(shè)置為FooModelBinder。

         1: public class HomeController : Controller
         2: {
         3:     public void Index()
         4:     {
         5:         ControllerDescriptor controllerDescriptor = new ReflectedControllerDescriptor(typeof(HomeController));
         6:         ActionDescriptor actionDescriptor = controllerDescriptor.FindAction(ControllerContext, "DoSomething");
         7:         IModelBinder foo = actionDescriptor.GetParameters().First(p => p.ParameterName == "foo").BindingInfo.Binder;
         8:         IModelBinder bar = actionDescriptor.GetParameters().First(p => p.ParameterName == "bar").BindingInfo.Binder;
         9:         IModelBinder baz = actionDescriptor.GetParameters().First(p => p.ParameterName == "baz").BindingInfo.Binder;
        10:  
        11:         Response.Write(string.Format("foo: {0}<br/>", null == foo? "N/A": foo.GetType().Name));
        12:         Response.Write(string.Format("bar: {0}<br/>", null == bar ? "N/A" : bar.GetType().Name));
        13:         Response.Write(string.Format("baz: {0}<br/>", null == baz ? "N/A" : baz.GetType().Name));
        14:     }
        15:  
        16:     public void DoSomething([ModelBinder(typeof(FooModelBinder))]Foo foo,Bar bar, Bar baz)
        17:     {}                
        18: }

      在默認(rèn)的Action方法Index中,我們針對HomeController類型的ReflectedControllerDescriptor對象并獲取到用于描述Action方法DoSomething的ActionDescriptor對象。最后我們通過該ActionDescriptor對象得到用于描述其三個參數(shù)的ParameterDescriptor對象,并將其ModelBinder類西國內(nèi)呈現(xiàn)出來。當(dāng)我們運(yùn)行該程序的時候,會在瀏覽器中產(chǎn)生如下的輸出結(jié)果,可以看出對于分別應(yīng)用在參數(shù)和參數(shù)類型上的ModelBinderAttribute特性,只有前者會對ParameterDescriptor的ModelBinder的選擇造成影響。

         1: foo: FooModelBinder
         2: bar: N/A
         3: baz: N/A

       

      三、ModelBinders

      如果我們不曾通過ModelBinderAttribute特性為某個Action方法參數(shù)的ModelBinder類型進(jìn)行顯式定制,默認(rèn)采用的Model是通過靜態(tài)類型ModelBinders來提供的。如下面的代碼片斷所示,ModelBinders具有一個靜態(tài)只讀屬性Binders,表示當(dāng)前注冊ModelBinder列表,其類型為ModelBinderDictionary。

         1: public static class ModelBinders
         2: {   
         3:     public static ModelBinderDictionary Binders { get; }
         4: }
         5:  
         6: public class ModelBinderDictionary : 
         7:   IDictionary<Type, IModelBinder>, 
         8:   ICollection<KeyValuePair<Type, IModelBinder>>, 
         9:   IEnumerable<KeyValuePair<Type, IModelBinder>>, 
        10:   IEnumerable
        11: {    
        12:     //其他成員
        13:     public IModelBinder GetBinder(Type modelType);
        14:    public virtual IModelBinder GetBinder(Type modelType, bool fallbackToDefault);
        15: }

      ModelBinderDictionary是一個以數(shù)據(jù)類型(Model類型)為Key,ModelBinder對象為Value的字典,即它定義了針對某種數(shù)據(jù)類型的ModelBinder。ModelBinderDictionary具有兩個GetBinder方法重載用于獲取針對某個數(shù)據(jù)類型的ModelBinder,布爾類型的參數(shù)fallbackToDefault表示在數(shù)據(jù)類型不存在的時候是否采用默認(rèn)的ModelBinder,基于默認(rèn)ModelBinder的后備機(jī)制會在第一個GetBinder方法重載中采用。在這里默認(rèn)ModelBinder類型為DefaultModelBinder。

      在為某個參數(shù)獲取相應(yīng)的ModelBinder的時候,如果對應(yīng)的ParameterDescriptor的ModelBinder不存在,則通過ModelBinders的靜態(tài)屬性Binders表示獲取到當(dāng)前注冊的ModelBinder列表的ModelBinderDictionary對象,并將參數(shù)類型作為參數(shù)調(diào)用其GetBinder方法獲取相應(yīng)ModelBinder對象。

      我們根據(jù)ModelBinder的提供機(jī)制對上面演示的實(shí)例進(jìn)行相應(yīng)的修改。我們在HomeConroller中添加了一個CheckModelBinder方法,三個參數(shù)分別表示用于描述相應(yīng)Action方法的ActionDescriptor對象、參數(shù)名稱和類型。在該方法中我們先獲取到用于描述制定參數(shù)的ParameterDescriptor對象,如果它具有相應(yīng)的ModelBinder,則將具體的類型名稱輸出,否則輸出通過ModelBinders獲取的針對參數(shù)類型的ModelBinder類型。

         1: public class HomeController : Controller
         2: {
         3:     //其他成員
         4:     public void Index()
         5:     {
         6:         ControllerDescriptor controllerDescriptor = new ReflectedControllerDescriptor(typeof(HomeController));
         7:         ActionDescriptor actionDescriptor = controllerDescriptor.FindAction(ControllerContext, "DoSomething");
         8:  
         9:         CheckModelBinder(actionDescriptor, "foo", typeof(Foo));
        10:         CheckModelBinder(actionDescriptor, "bar", typeof(Bar));
        11:         CheckModelBinder(actionDescriptor, "baz", typeof(Baz));           
        12:     }
        13:  
        14:     private void CheckModelBinder(ActionDescriptor actionDescriptor, string parameterName, Type modelType)
        15:     { 
        16:         ParameterDescriptor parameterDescriptor = actionDescriptor.GetParameters().First(p=>p.ParameterName == parameterName);
        17:         IModelBinder modelBinder = parameterDescriptor.BindingInfo.Binder ?? ModelBinders.Binders.GetBinder(modelType);
        18:         Response.Write(string.Format("{0}: {1}<br/>", parameterName, null == modelBinder ? "N/A" : modelBinder.GetType().Name));
        19:     }
        20: }

      在Index方法中,我們調(diào)用CheckModelBinder方法將Action方法DoSomething的三個參數(shù)對應(yīng)的ModelBinder類型呈現(xiàn)出來。當(dāng)我們運(yùn)行該程序的時候,在瀏覽器上會得到如下的輸出結(jié)果,應(yīng)用在類型Bar上的BarModelBinder會用于針對參數(shù)bar的Model綁定,而參數(shù)baz則會使用默認(rèn)的DefaultModelBinder。

         1: foo: FooModelBinder
         2: bar: BarModelBinder
         3: baz: DefaultModelBinder

      對于上面的這個例子,由于數(shù)據(jù)類型Baz沒有關(guān)聯(lián)ModelBinder注冊到通過ModelBinders的靜態(tài)屬性Binders表示的全局ModelBinder列表中,所以才導(dǎo)致DoSomething的baz參數(shù)采用默認(rèn)的DefaultModelBinder。如果我們實(shí)現(xiàn)針對數(shù)據(jù)類型Baz進(jìn)行了相應(yīng)的ModelBinder注冊,那么被注冊的ModelBinder將會自動用于該類型參數(shù)的Model綁定。同樣是針對上面演示的這個實(shí)例,我們定義了如下一個實(shí)現(xiàn)了IModelBinder的BazModelBinder。

         1: public class BazModelBinder : IModelBinder
         2: {
         3:     public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
         4:     {
         5:         throw new NotImplementedException();
         6:     }
         7: }

      現(xiàn)在我們希望使用這個BazModelBinder用于針對所有類型為Bar的參數(shù)的Model綁定,那么我們可以通過Global.asax在應(yīng)用啟動的時候進(jìn)行如下的ModelBinder注冊。

         1: public class MvcApplication : System.Web.HttpApplication
         2: {
         3:     //其他成員
         4:     protected void Application_Start()
         5:     {
         6:         //其他操作
         7:         ModelBinders.Binders.Add(typeof(Baz), new BazModelBinder());
         8:     }
         9: }

      再次運(yùn)行我們的程序,在瀏覽器中會得到如下的輸出結(jié)果,從中可以清楚地看出我們注冊的BazModelBinder并用于baz參數(shù)的Model綁定。

         1: foo: FooModelBinder
         2: bar: BarModelBinder
         3: baz: BazModelBinder

       

      四、ModelBinderProvider

      ASP.NET MVC的Model綁定系統(tǒng)還涉及到另一個重要的組件ModelBinderProvider。顧名思義,ModelBinderProvider專門用于提供相應(yīng)的ModelBinder對象,它們均實(shí)現(xiàn)了IModelBinderProvider面的代碼片斷所示,IModelBinderProvider接口定義了唯一的GetBinder方法用于根據(jù)數(shù)據(jù)類型獲取相應(yīng)的ModelBinder對象。不過在ASP.NET MVC現(xiàn)有的應(yīng)用編程接口中并沒有定義任何一個實(shí)現(xiàn)該接口的ModelBinderProvider類型。

         1: public interface IModelBinderProvider
         2: {    
         3:     IModelBinder GetBinder(Type modelType);
         4: }

      我們可以利用ModelBinderProviders為應(yīng)用注冊一組ModelBinderProvider對象為某個數(shù)據(jù)類型提供相應(yīng)的ModelBinder。如下面的代碼片斷所示,靜態(tài)類型ModelBinderProviders具有一個靜態(tài)只讀屬性BinderProviders,其類型ModelBinderProviderCollection實(shí)際上是一個型ModelBinderProvider的集合,該集合表示針對當(dāng)前應(yīng)用的ModelBinderProvider列表。

         1: public static class ModelBinderProviders
         2: {    
         3:     public static ModelBinderProviderCollection BinderProviders { get; }
         4: }
         5:  
         6: public sealed class ModelBinderProviderCollection : Collection<IModelBinderProvider>
         7: {
         8:     //省略成員
         9: }

      通過ModelBinderProviders的靜態(tài)屬性BinderProviders表示的ModelBinderProvider列表最終被ModelBinderDictionary使用。如下面的代碼片斷所示,ModelBinderDictionary除了具有一個表示基于數(shù)據(jù)類型的ModelBinder字典(_innerDictionary字段)和一個默認(rèn)ModelBinder(_defaultBinder)之外,還具有一個ModelBinderProvider列表(_modelBinderProviders字段)。

         1: public class ModelBinderDictionary
         2: {
         3:     //其他成員
         4:     private IModelBinder _defaultBinder;
         5:     private readonly Dictionary<Type, IModelBinder> _innerDictionary;
         6:     private ModelBinderProviderCollection _modelBinderProviders;   
         7: }

      當(dāng)ModelBinderDictionary被創(chuàng)建的時候,通過ModelBinderProviders的靜態(tài)屬性BinderProviders表示的ModelBinderProvider列表會用于初始化_modelBinderProviders字段。圍繞著ModelBinder的Model綁定系統(tǒng)中的核心組件之間的關(guān)系基本上可以通過下圖所示的UML來表示。

      image

      當(dāng)我們調(diào)用GetBinder或者指定數(shù)據(jù)類型對應(yīng)的ModelBinder時,_innerDictionary字段表示的ModelBinder字典會被優(yōu)先選擇。如果數(shù)據(jù)類型在該字典中找不到,則選擇使用通過_modelBinderProviders字段表示的ModelBinderProvider列表進(jìn)行ModelBinder的提供。只有在兩種ModelBinder提供方式均失敗的情況下才會選擇通過_innerDictionary字段表示的默認(rèn)ModelBinder。也就是說,如果我們想為某個數(shù)據(jù)類型定制某種類型的ModelBinder,按照選擇優(yōu)先級具有如下幾種方式供我們選擇:

      • 將ModelBinderAttribute應(yīng)用在Action方法的相應(yīng)參數(shù)上并指定相應(yīng)的ModelBinder類型,或者在參數(shù)上應(yīng)用一個自定義的CustomModelBinderAttribute特性。
      • 通過ModelBinders的靜態(tài)屬性Binders實(shí)現(xiàn)針對基于某種數(shù)據(jù)類型的ModelBinder注冊。
      • 自定義ModelBinderProvider實(shí)現(xiàn)基于某個數(shù)據(jù)類型的ModelBinder提供機(jī)制,并通過注冊當(dāng)通過ModelBinderProviders的靜態(tài)屬性BinderProviders表示的ModelBinderProvider列表中。
      • 將ModelBinderAttribute應(yīng)用在數(shù)據(jù)類型上并制定相應(yīng)的ModelBinder類型,或者在數(shù)據(jù)類型上應(yīng)用一個自定義的CustomModelBinderAttribute特性。

      前面三種方式的ModelBinder提供機(jī)制我們已經(jīng)通過實(shí)例演示過了,現(xiàn)在我們來演示基于自定義ModelBinderProvider的ModelBinder提供機(jī)制。在前面的例子中我們?yōu)镕oo、Bar和Baz這三種數(shù)據(jù)類型創(chuàng)建了相應(yīng)的ModelBinder(FooModelBinder、BarModelBinder和BazModelBinder),現(xiàn)在我們創(chuàng)建如下一個自定義的ModelBinderProvider將兩種(數(shù)據(jù)類型和ModelBinder對象)進(jìn)行關(guān)聯(lián)。

         1: public class MyModelBinderProvider : IModelBinderProvider
         2: {
         3:     public IModelBinder GetBinder(Type modelType)
         4:     {
         5:         if (modelType == typeof(Foo))
         6:         {
         7:             return new FooModelBinder();
         8:         }
         9:         if (modelType == typeof(Bar))
        10:         {
        11:             return new BazModelBinder();
        12:         }
        13:         if (modelType == typeof(Baz))
        14:         {
        15:             return new BazModelBinder();
        16:         }
        17:         return null;
        18:     }
        19: }

      現(xiàn)在我們需要通過利用Global.asax通過如下的方式在應(yīng)用啟動時將一個我們自定義的MyModelBinderProvider注冊到通過ModelBinderProviders的靜態(tài)屬性BinderProviders表示的ModelBinderProvider列表中。

         1: public class MvcApplication : System.Web.HttpApplication
         2: {
         3:     //其他成員
         4:     protected void Application_Start()
         5:     {
         6:         //其他操作
         7:        ModelBinderProviders.BinderProviders.Add(new MyModelBinderProvider());
         8:     }
         9: }

      由于MyModelBinderProvider實(shí)現(xiàn)了針對Foo、Bar和Baz三種數(shù)據(jù)類型的ModelBinder的提供,所以我們可以將應(yīng)用在Action方法參數(shù)和數(shù)據(jù)類型上的ModelBinderAttribute特性刪除。再次運(yùn)行我們的程序,會在瀏覽器中得到如下的輸出結(jié)果,從中可以看到DoSomething方法的三個參數(shù)此時采用了我們期望的ModelBinder類型。

         1: foo: FooModelBinder
         2: bar: BarModelBinder
         3: baz: BazModelBinder
      posted @ 2012-05-21 08:12  Artech  閱讀(27416)  評論(12)    收藏  舉報
      主站蜘蛛池模板: 国产线播放免费人成视频播放| 国产特级毛片aaaaaa毛片| 色色97| 久久人人妻人人爽人人爽| 国产成人高清亚洲一区91| 正在播放国产真实哭都没用| 99久久精品国产一区二区蜜芽| 亚洲国产精品日韩AV专区| 亚洲一区二区三区| 国产精品久久久一区二区三区| 精品偷拍一区二区三区在| 国产成a人亚洲精v品无码性色| 久久综合色之久久综合色| 国产欧美一区二区日本加勒比| free性开放小少妇| 亚洲国产免费图区在线视频| 少妇极品熟妇人妻无码| 亚洲日韩精品一区二区三区无码| 九九热在线视频观看这里只有精品 | 国产一精品一av一免费| 国语精品国内自产视频| 亚洲美免无码中文字幕在线| 精品一区二区三人妻视频| 老熟妇乱子交视频一区| 99er热精品视频| 人妻少妇88久久中文字幕| 国产精品成人久久电影| 亚洲人妻一区二区精品| 日本伊人色综合网| 99久久精品免费看国产电影| 欧美和黑人xxxx猛交视频| 国产破外女出血视频| 国产精品天干天干综合网| 精品国产综合一区二区三区| 成年女人免费碰碰视频| 农村老熟妇乱子伦视频| 97精品人妻系列无码人妻| 久久天天躁狠狠躁夜夜avapp | 久久成人 久久鬼色| 久热综合在线亚洲精品| 无码日韩av一区二区三区|