在《ASP.NET MVC的Razor引擎:RazorView》介紹BuildManagerCompiledView的時候,我們談到預設使用的ViewPageActivator使用當前註冊的DependencyResolver來完成對目標View的啟用,這意味著我們可以通過註冊自訂DependencyResolver的方式實現基於IoC的View啟用。本篇文章中我們將示範如何通過自訂View的方式實現與IoC架構Ninject的整合。
我們定義了一個具有如下定義的NinjectDependencyResolver,它具有一個IKernel類型的唯讀屬性Kernel,該屬性在建構函式中被初始化為一個StandardKernel對象。對於實現的GetService和GetServices方法,我們直接調用Kernel的TryGet和GetAll返回指定類型的執行個體和執行個體列表。為了方便進行類型映射,我們定義了泛型的Register<TFrom,TTo>方法。
1: public class NinjectDependencyResolver : IDependencyResolver
2: {
3: public IKernel Kernel { get; private set; }
4: public NinjectDependencyResolver()
5: {
6: this.Kernel = new StandardKernel();
7: }
8: public void Register<TFrom, TTo>() where TTo: TFrom
9: {
10: this.Kernel.Bind<TFrom>().To<TTo>();
11: }
12: public object GetService(Type serviceType)
13: {
14: return this.Kernel.TryGet(serviceType);
15: }
16: public IEnumerable<object> GetServices(Type serviceType)
17: {
18: return this.Kernel.GetAll(serviceType);
19: }
20: }
我們示範的是一個針對多語言支援的情境,為了讓View上輸出的一些內容隨著當前線程的UICulture而動態地變化,我們在一個ASP.NET MVC應用中定義如下一個讀取資源內容抽象類別ResourceReader。這裡資源是一個寬泛的概念,並不對儲存方式作強制的約束,我們可以使用資源檔也可以使用資料庫來儲存資源內容。簡單起見,ResourceReader僅僅定義了一個唯一GetString方法擷取指定名稱的字串。
1: public abstract class ResourceReader
2: {
3: public abstract string GetString(string name);
4: }
我們預設採用資源檔來定義資料來源,為此我們在項目中添加了兩個資源檔Resoures.resx(語言文化中性)和Resources.zh.resx(中文),並在資源檔中添加了如下圖所示的資源項(HelloWorld)。
然後我們建立如下一個預設的DefaultResourceReader,它預設讀取我們添加的資源檔來擷取GetString方法返回的字串(靜態類型Resources是添加資源檔自動建立的類型)。
1: public class DefaultResourceReader : ResourceReader
2: {
3: public override string GetString(string name)
4: {
5: return Resources.ResourceManager.GetString(name);
6: }
7: }
為了讓ResourceManager能夠應用到所有的View中,我們為整個應用的View建立了如下一個基類LocalizableViewPage<TModel>。該類型是WebViewPage<TModel>的子類,它具有一個類型為ResourceManager的屬性ResourceManager。由於該屬性上應用了Ninject.InjectAttribute特性,意味著該屬性會以“屬性注入”的方式被自動初始化。
1: public abstract class LocalizableViewPage<TModel>: WebViewPage<TModel>
2: {
3: [Inject]
4: public ResourceReader ResourceReader { get; set; }
5: }