程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> ASP.NET >> 關於ASP.NET >> ModelBinder:ASP.NET MVC Model綁定的核心

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

編輯:關於ASP.NET

Model的綁定體現在從當前請求提取相應的數據綁定到目標Action方法的參數。通過前面的介紹我們知道Action方法的參數通過ParameterDescriptor來描述,ParameterDescriptor的BindingInfo屬性表示的ParameterBindingInfo對象具有一個名為ModelBinder的組件用於完成針對當前參數的Model綁定。ModelBinder可以看成是整個Model綁定系統的核心,我們先來認識這個重要的組件。

一、 ModelBinder

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

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

IModelBinder的BindModel方法接受兩個參數,一個是表示當前的Controller上下文,另一個是表示針對當前Model綁定的上下文,通過類型ModelBindingContext表示。在Controller初始化的時候,Controller上下文已經被創建出來,所以我們只要能夠針對當前的Model綁定創建相應的ModelBindingContext,我們就能使用基於某個參數的ModelBinder得到對應的參數值。關於ModelBindingContext的創建我們會在後續部分進行的單獨介紹,我們先來介紹一下ModelBinder的提供機制。

二、CustomModelBinderAttribute與ModelBinderAttribute

如果針對某個參數的ParameterDescriptor具有相應的ModelBinder,那麼它會被優先選擇用於針對該參數的Model綁定,那麼ParameterDescriptor的ModelBinder是如何來提供的呢?這是實際上設置一個具有如下定義的CustomModelBinderAttribute特性。抽象類CustomModelBinderAttribute定義了唯一的抽象方法GetBinder用於獲取相應的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應用編程接口中,CustomModelBinderAttribute具有一個具有如下定義的唯一繼承類型ModelBinderAttribute。我們可以通過應用ModelBinderAttribute特性動態地選擇用於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: }

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

為了演示ModelBinderAttribute特性對ParameterDescriptor的影響,我們來進行一個簡單的實例演示。在一個通過Visual Studio的ASP.NET MVC項目模板創建的空Web應用中定義了如下幾個類型,其中FooModelBinder和BarModelBinder是顯現了IModelBinder的自定義ModelBinder類型,而Foo、Bar和Baz是三個將被作為Action方法參數的數據類型,其中Bar上應用了ModelBinderAttribute特性並將ModelBinder類型設置為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 { }

然後再創建的默認HomeController中定義如下兩個Action方法。DoSomething方法具有三個參數,類型分別是Foo、Bar和Baz,在第一個參數上應用了ModelBinderAttribute特性並將ModelBinder類型設置為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: }

在默認的Action方法Index中,我們針對HomeController類型的ReflectedControllerDescriptor對象並獲取到用於描述Action方法DoSomething的ActionDescriptor對象。最後我們通過該ActionDescriptor對象得到用於描述其三個參數的ParameterDescriptor對象,並將其ModelBinder類西國內呈現出來。當我們運行該程序的時候,會在浏覽器中產生如下的輸出結果,可以看出對於分別應用在參數和參數類型上的ModelBinderAttribute特性,只有前者會對ParameterDescriptor的ModelBinder的選擇造成影響。

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

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved