看過前兩篇的朋友想必對Model綁定有個大概的了解,然而MVC架構給我們提供了更高的可擴充性的提供程式程式設計模式,也就是本篇的主題了,會講解一下Model綁定器提供程式的實作以及解決一下上篇遺留的問題。
第一個問題是ModelBinderProviderCollection類型的執行過程?
還有個本篇的問題就是同樣的向系統上下文中注冊Model綁定器和Model綁定器提供程式,哪一個優先級更高?
IModelBinder、自定義Model綁定器簡單實作
Model綁定器在MVC架構中的位置
MVC中的預設Model綁定器生成過程
IModelBinderProvider的簡單應用
IValueProvider在MVC架構中生成的位置以及過程
IValueProvider的應用場景
IValueProvider的實作之NameValueCollectionValueProvider
首先我們先看一下IModelBinderProvider類型的定義,代碼1-1:。
代碼1-1
1
2
3
4
5
6
7
8
9
10
11
12
13
<code> </code><code>public</code> <code>interface</code> <code>IModelBinderProvider</code>
<code> </code><code>{</code>
<code> </code><code>// 摘要:</code>
<code> </code><code>// 傳回指定類型的模型聯程式設計式。</code>
<code> </code><code>//</code>
<code> </code><code>// 參數:</code>
<code> </code><code>// modelType:</code>
<code> </code><code>// 模型的類型。</code>
<code> </code><code>// 傳回結果:</code>
<code> </code><code>// 指定類型的模型聯程式設計式。</code>
<code> </code><code>IModelBinder GetBinder(Type modelType);</code>
<code> </code><code>}</code>
在代碼1-1中我們看出,其中的GetBinder()方法是根據ViewModel的類型來做一些操作,最後傳回Model綁定器。現在我們自定義實作一個Model綁定器提供程式代碼1-2。
代碼1-2
14
15
16
17
18
19
20
21
<code>using</code> <code>System.Web.Mvc;</code>
<code>using</code> <code>ConsoleApplication2;</code>
<code>namespace</code> <code>MvcApplication.Infrastructure</code>
<code>{</code>
<code> </code><code>public</code> <code>class</code> <code>MyCustomModelBinderProvider : IModelBinderProvider</code>
<code> </code><code>public</code> <code>IModelBinder GetBinder(Type modelType)</code>
<code> </code><code>{</code>
<code> </code><code>if</code> <code>(modelType == </code><code>null</code><code>)</code>
<code> </code><code>{</code>
<code> </code><code>throw</code> <code>new</code> <code>ArgumentNullException(</code><code>"modelType"</code><code>);</code>
<code> </code><code>}</code>
<code> </code><code>if</code> <code>(modelType == </code><code>typeof</code><code>(Customer))</code>
<code> </code><code>//傳回對應Customer類型的Model綁定器</code>
<code> </code><code>return</code> <code>null</code><code>;</code>
<code> </code><code>}</code>
<code>}</code>
在代碼1-2中我們根據modelType判斷是否是Customer類型,然後傳回對應Customer類型的Model綁定器。為什麼這裡的實作是空的,因為我想把我們前面講解過的IoC架構用起來,讓Model綁定器提供程式跟Model綁定器解除耦合,想把IoC架構的應用定義在目前系統的上下文中,我們看一下代碼實作,代碼1-3。
代碼1-3
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<code>namespace</code> <code>MvcApplication</code>
<code> </code><code>public</code> <code>class</code> <code>MVCSystemContext</code>
<code> </code><code>private</code> <code>static</code> <code>MVCSystemContext _MVCSystemContext;</code>
<code> </code><code>public</code> <code>static</code> <code>MVCSystemContext Context</code>
<code> </code><code>get</code>
<code> </code><code>if</code> <code>(_MVCSystemContext == </code><code>null</code><code>)</code>
<code> </code><code>{</code>
<code> </code><code>_MVCSystemContext = </code><code>new</code> <code>MVCSystemContext();</code>
<code> </code><code>}</code>
<code> </code><code>return</code> <code>_MVCSystemContext;</code>
<code> </code><code>private</code> <code>ServiceContainer _serviceContainer;</code>
<code> </code><code>private</code> <code>MVCSystemContext()</code>
<code> </code><code>_serviceContainer = </code><code>new</code> <code>ServiceContainer();</code>
<code> </code><code>_serviceContainer.AddService(</code><code>typeof</code><code>(NinjectController),NinjectController.Instance);</code>
<code> </code><code>public</code> <code>NinjectController NinjectController</code>
<code> </code><code>return</code> <code>(NinjectController)_serviceContainer.GetService(</code><code>typeof</code><code>(NinjectController));</code>
代碼1-3當中就是我定義的目前系統上下文了,隻不過這個是給自己用的,上下文對象中想必是不會把所用到的所有資料或者是功能都添加在裡面的,隻是添加個引用而已,如代碼1-3中的NinjectController屬性,NinjectController屬性對應的類型就是NinjectController類型,NinjectController類型的作用就是提供IoC架構的功能,我們看一下代碼1-4中對于NinjectController類型的定義。
代碼1-4
<code>using</code> <code>Ninject;</code>
<code>namespace</code> <code>MvcApplication.Infrastructure.NinjectControllerPart</code>
<code> </code><code>public</code> <code>class</code> <code>NinjectController</code>
<code> </code><code>private</code> <code>static</code> <code>NinjectController _Instance;</code>
<code> </code><code>public</code> <code>static</code> <code>NinjectController Instance</code>
<code> </code><code>get</code>
<code> </code><code>return</code> <code>_Instance = </code><code>new</code> <code>NinjectController();</code>
<code> </code><code>private</code> <code>IKernel _ninjectKernel;</code>
<code> </code><code>private</code> <code>NinjectController()</code>
<code> </code><code>_ninjectKernel = </code><code>new</code> <code>StandardKernel();</code>
<code> </code><code>public</code> <code>void</code> <code>AddKernelBind<T, U>()</code><code>where</code> <code>U:T</code>
<code> </code><code>_ninjectKernel.Bind<T>().To<U>();</code>
<code> </code><code>public</code> <code>T GetValueType<T>(Type keyType)</code>
<code> </code><code>var</code> <code>valueType = _ninjectKernel.Get(keyType);</code>
<code> </code><code>return</code> <code>(T)valueType;</code>
其中對于Ninject這個IoC架構進行了一個最基礎的功能封裝,有的朋友可能會問為什麼不公開個一個屬性,何必這樣多此一舉,因為我對Ninject的使用也不是很熟練,對于這部分的封裝我隻是讓其簡單的公開了兩個功能,一個是綁定一個是擷取值,這樣讓這部分内容還在我的可控範圍内,如果是公開屬性的話,其他人的胡亂使用導緻錯誤的話是不可控的。
切回主題,這樣基礎定義好了過後,我們再修改1-2中的代碼,把具體實作給加上,示例代碼1-5所示。
代碼1-5
<code>if</code> <code>(modelType == </code><code>typeof</code><code>(Customer))</code>
<code> </code><code>//傳回對應Customer類型的Model綁定器</code>
<code> </code><code>return</code> <code>MVCSystemContext.Context.NinjectController.GetValueType<IModelBinder>(</code><code>typeof</code><code>(IModelBinder));</code>
可以看到代碼1-5中,根據我們自定義上下文中的提供的IoC功能擷取到綁定在IoC架構中的值,那麼綁定又是在哪裡呢?跟ASP.NET MVC Model綁定(一)所示範的那樣,還是在項目的Global.asax檔案中的MvcApplication類型的Application_Start()方法中添加如代碼1-6。
代碼1-6
<code>MVCSystemContext.Context.NinjectController.AddKernelBind<IModelBinder, Binders.MyCustomModelBinder>();</code>
<code>ModelBinderProviders.BinderProviders.Add(</code><code>new</code> <code>MyCustomModelBinderProvider());</code>
代碼1-6分别做了兩個操作,先是把對應Customer類型的Model綁定器注冊到了我們自定義上下文的IoC中,然後再把針對處理Customer類型的Model綁定器提供程式注冊到系統中。運作結果如圖1.
圖1

其中涉及到所有部分的代碼和ASP.NET MVC Model綁定(一)篇幅中的一樣,是以這裡就沒有列舉了。
在此我們根據上篇中最後圖2所示的那樣,可以判斷出ModelBinderProviderCollection類型的執行過程是根據目前ParameterDescriptor類型所提供的Model類型對比我們注冊到或者是系統預設提供的Model綁定器提供程式集合,如果有是針對ParameterDescriptor類型所提供的Model類型(上述示例中是Customer類型)則會有Model綁定器的傳回,然後再根據Model綁定器進行Model綁定。
好了現在第一個問題解決了,來解決第二個問題。來看代碼1-7所示。
代碼1-7
<code>public</code> <code>class</code> <code>MyCustomModelBinder:IModelBinder</code>
<code> </code><code>public</code> <code>object</code> <code>BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)</code>
<code> </code><code>return</code> <code>new</code> <code>Customer()</code>
<code> </code><code>CustomerID = </code><code>"010"</code><code>,</code>
<code> </code><code>Name = </code><code>"測試人員"</code><code>,</code>
<code> </code><code>RegistrationDate = DateTime.Now,</code>
<code> </code><code>Address = </code><code>new</code> <code>Address()</code>
<code> </code><code>AddressName = </code><code>"天空之城"</code>
<code> </code><code>};</code>
<code> </code><code>public</code> <code>class</code> <code>MyCustomModelBinder_Test : IModelBinder</code>
<code> </code><code>AddressName = </code><code>"這裡是根據Model綁定器綁定執行的Model"</code>
看到代碼1-7中的MyCustomModelBinder_Test 類型内部Customer類型執行個體内部的AddressName值已經更改的和之前的不一樣了。再看一***冊端的修改,示例代碼1-8。
代碼1-8
<code>ModelBinders.Binders.Add(</code><code>typeof</code><code>(Customer), </code><code>new</code> <code>Binders.MyCustomModelBinder_Test());</code>
代碼1-8中,我們把新定義的MyCustomModelBinder_Test 類型注冊到了系統的Model綁定器集合中,看一下究竟是哪一個級别更高一點。
來看運作結果圖2
圖2
看到圖2這個結果,想必已經知道了是哪個級别更高一點了。
本文轉自jinyuan0829 51CTO部落格,原文連結:http://blog.51cto.com/jinyuan/1432752,如需轉載請自行聯系原作者