ASP.NET MVC 2擴展點之Controller Factory
Asp.net mvc2中提供很多可以擴展的地方,利用這些擴展之后,asp.net mvc使用起來更加靈活。Simone Chiaretta曾寫過一篇文章:13 ASP.NET MVC extensibility points you have to know。文章中概括性的介紹了13個asp.net mvc開發人員必須知道的擴展點。我將從這13個擴展點中挑選幾個常見的重要的擴展點進行詳細的介紹。這篇將文章將首先介紹Controller Factory。
Controller Factory是Asp.MVC框架中一個重要的擴展點。Controller Factory是用來創建控制器。而Controller最常用的場景之一是支持依賴注入。但是如果直接在控制器中使用依賴注入,默認情況下asp.net mvc框架將不會為你創建Controller,而且你還會得到下面這個錯誤,如下圖:
產生上面錯誤的原因是DefaultControllerFactory使用Activator.CreateInstance來初始化控制器,而這個方法對你依賴注入的參數一無所知。
這種情況下,我們就要使用自定義的Controller Factory。
一個自定義的Controller Factory需要繼承IControllerFactory或者繼承過IControllerFactory的類,如:DefaultControllerFactory。下面代碼是一個自定義的Controller factory。
public class MyCustomControllerFactory : DefaultControllerFactory { protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType) { /* implement controller creation logic */ return base.GetControllerInstance(requestContext, controllerType); } }
在定義Controller Factory之后,需要在Application_Start()中注冊一下:
ControllerBuilder.Current.SetControllerFactory(new MyCustomControllerFactory());
這樣MVC框架將會使用你自定的Controller Factory創建Controller。
看下面這個ProductsController,這個控制器在構造函數中接受依賴注入:
public class ProductsController : Controller { public ProductsController(IProductRepository repository,IShippingCalculator shippingCalculator, ITaxService taxService) { /* ... */ } /* ... */ }
如果自己手動寫代碼創建這樣的Controller是非常乏味的。幸運的是我們不需要自己手寫代碼去實現。因為存在很多IoC工具供我們使用。在.net中最好的依賴注入工具之一便是StructureMap,它是一個輕量級開源免費IOC框架。下面我將使用這個工具實現一個簡單的MVC中依賴注入的Demo。
1、到http://structuremapsourceforge.net/上下載這個工具。在MVC項目中引用StructureMap.dll。
2、在Models中定義一個依賴注入的IMessageProvider接口,以及它的一個實現類StructureMapMessageProvider。
namespace MvcApplication1.Models { public interface IMessageProvider { string GetMessage(); } public class StructureMapMessageProvider : IMessageProvider { public string GetMessage() { return "This message was provided by StructureMap"; } } }
3、利用StructureMap自定義的Controller Factory代碼如下:
public class StructureMapControllerFactory : DefaultControllerFactory { protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType) { return ObjectFactory.GetInstance(controllerType) as IController; } }
4、定義一個靜態類StructureMapBootstrapper,用來初始化StructureMap和設置StructureMapControllerFactory為項目的Controller Factory,代碼如下:
public static class StructureMapBootstrapper { public static void Initialize() { ObjectFactory.Initialize(x => x.AddRegistry(new MyStructureMapApplicationRegistry())); } public static void SetControllerFactory() { var controllerFactory = new StructureMapControllerFactory(); ControllerBuilder.Current.SetControllerFactory(controllerFactory); } }
5、在Global.asax中使用上面的StructureMapBootstrapper類設置Controller Factory和初始化StructureMap。
StructureMapBootstrapper.SetControllerFactory(); StructureMapBootstrapper.Initialize();
6、這樣我們就能正常使用了。我們將HomeController設置如下:
[HandleError] public class HomeController : Controller { private IMessageProvider _messageProvider; public HomeController(IMessageProvider messageProvider) { _messageProvider = messageProvider; } public ActionResult Index() { ViewData["Message"] = _messageProvider.GetMessage(); return View(); } }
運行結果如下:
總結:本文簡單的介紹了一下自定義Controller Factory。
參考:asp.net mvc 2 in action