標籤:asp.net mvc mvc .net c# modelbinder
ASP.NET MVC Model綁定(三)
前言
看過前兩篇的朋友想必對Model綁定有個大概的瞭解,然而MVC架構給我們提供了更高的可擴充性的提供者編程模式,也就是本篇的主題了,會講解一下Model綁定器提供者的實現以及解決一下上篇遺留的問題。
第一個問題是ModelBinderProviderCollection類型的執行過程?
還有個本篇的問題就是同樣的向系統上下文中註冊Model綁定器和Model綁定器提供者,哪一個優先順序更高?
Model綁定
- IModelBinder、自訂Model綁定器簡單實現
- Model綁定器在MVC架構中的位置
- MVC中的預設Model綁定器產生過程
- IModelBinderProvider的簡單應用
- IValueProvider在MVC架構中產生的位置以及過程
- IValueProvider的應用情境
- IValueProvider的實現之NameValueCollectionValueProvider
IModelBinderProvider的簡單應用
首先我們先看一下IModelBinderProvider類型的定義,代碼1-1:。
代碼1-1
public interface IModelBinderProvider { // 摘要: // 返回指定類型的模型聯編程式。 // // 參數: // modelType: // 模型的類型。 // // 返回結果: // 指定類型的模型聯編程式。 IModelBinder GetBinder(Type modelType); }
在代碼1-1中我們看出,其中的GetBinder()方法是根據ViewModel的類型來做一些操作,最後返回Model綁定器。現在我們自訂實現一個Model綁定器提供者代碼1-2。
代碼1-2
using System.Web.Mvc;using ConsoleApplication2;namespace MvcApplication.Infrastructure{ public class MyCustomModelBinderProvider : IModelBinderProvider { public IModelBinder GetBinder(Type modelType) { if (modelType == null) { throw new ArgumentNullException("modelType"); } if (modelType == typeof(Customer)) { //返回對應Customer類型的Model綁定器 } return null; } }}
在代碼1-2中我們根據modelType判斷是否是Customer類型,然後返回對應Customer類型的Model綁定器。為什麼這裡的實現是空的,因為我想把我們前面講解過的IoC架構用起來,讓Model綁定器提供者跟Model綁定器解除耦合,想把IoC架構的應用定義在當前系統的上下文中,我們看一下代碼實現,代碼1-3。
代碼1-3
using System.Web.Mvc;using Ninject;using System.ComponentModel;using System.ComponentModel.Design;using MvcApplication.Infrastructure.NinjectControllerPart;namespace MvcApplication{ public class MVCSystemContext { private static MVCSystemContext _MVCSystemContext; public static MVCSystemContext Context { get { if (_MVCSystemContext == null) { _MVCSystemContext = new MVCSystemContext(); } return _MVCSystemContext; } } private ServiceContainer _serviceContainer; private MVCSystemContext() { _serviceContainer = new ServiceContainer(); _serviceContainer.AddService(typeof(NinjectController),NinjectController.Instance); } public NinjectController NinjectController { get { return (NinjectController)_serviceContainer.GetService(typeof(NinjectController)); } } }}
代碼1-3當中就是我定義的當前系統上下文了,只不過這個是給自己用的,內容物件中想必是不會把所用到的所有資料或者是功能都添加在裡面的,只是添加個引用而已,如代碼1-3中的NinjectController屬性,NinjectController屬性對應的類型就是NinjectController類型,NinjectController類型的作用就是提供IoC架構的功能,我們看一下代碼1-4中對於NinjectController類型的定義。
代碼1-4
using Ninject;namespace MvcApplication.Infrastructure.NinjectControllerPart{ public class NinjectController { private static NinjectController _Instance; public static NinjectController Instance { get { return _Instance = new NinjectController(); } } private IKernel _ninjectKernel; private NinjectController() { _ninjectKernel = new StandardKernel(); } public void AddKernelBind<T, U>()where U:T { _ninjectKernel.Bind<T>().To<U>(); } public T GetValueType<T>(Type keyType) { var valueType = _ninjectKernel.Get(keyType); return (T)valueType; } }}
其中對於Ninject這個IoC架構進行了一個最基礎的功能封裝,有的朋友可能會問為什麼不公開個一個屬性,何必這樣多此一舉,因為我對Ninject的使用也不是很熟練,對於這部分的封裝我只是讓其簡單的公開了兩個功能,一個是綁定一個是擷取值,這樣讓這部分內容還在我的可控範圍內,如果是公開屬性的話,其他人的胡亂使用導致錯誤的話是不可控的。
切回主題,這樣基礎定義好了過後,我們再修改1-2中的代碼,把具體實現給加上,範例程式碼1-5所示。
代碼1-5
if (modelType == typeof(Customer)){ //返回對應Customer類型的Model綁定器 return MVCSystemContext.Context.NinjectController.GetValueType<IModelBinder>(typeof(IModelBinder));}
可以看到代碼1-5中,根據我們自訂上下文中的提供的IoC功能擷取到綁定在IoC架構中的值,那麼綁定又是在哪裡呢?跟ASP.NET MVC Model綁定(一)所示範的那樣,還是在項目的Global.asax檔案中的MvcApplication類型的Application_Start()方法中添加如代碼1-6。
代碼1-6
MVCSystemContext.Context.NinjectController.AddKernelBind<IModelBinder, Binders.MyCustomModelBinder>();ModelBinderProviders.BinderProviders.Add(new MyCustomModelBinderProvider());
代碼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
public class MyCustomModelBinder:IModelBinder { public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { return new Customer() { CustomerID = "010", Name = "測試人員", RegistrationDate = DateTime.Now, Address = new Address() { AddressName = "天空之城" } }; } } public class MyCustomModelBinder_Test : IModelBinder { public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { return new Customer() { CustomerID = "010", Name = "測試人員", RegistrationDate = DateTime.Now, Address = new Address() { AddressName = "這裡是根據Model綁定器綁定執行的Model" } }; } }
看到代碼1-7中的MyCustomModelBinder_Test 類型內部Customer類型執行個體內部的AddressName值已經更改的和之前的不一樣了。再看一下註冊端的修改,範例程式碼1-8。
代碼1-8
ModelBinders.Binders.Add(typeof(Customer), new Binders.MyCustomModelBinder_Test());MVCSystemContext.Context.NinjectController.AddKernelBind<IModelBinder, Binders.MyCustomModelBinder>();ModelBinderProviders.BinderProviders.Add(new MyCustomModelBinderProvider());
代碼1-8中,我們把新定義的MyCustomModelBinder_Test 類型註冊到了系統的Model綁定器集合中,看一下究竟是哪一個層級更高一點。
來看運行結果圖2
圖2
看到圖2這個結果,想必已經知道了是哪個層級更高一點了。
金源
出處:http://blog.csdn.net/jinyuan0829
本文著作權歸作者和CSDN共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面