上面這張圖是asp.net mvc的工作流程圖,我們可以看到當一個http請求來臨時,首先需要經過路由系統,路由系統從中獲取一些路由信息,然后ControllerFactory根據所得到的路由信息生成相應的Controller。也就是說,ControllerFactory的作用就是根據路由信息生成相應的Controller。
1.ASP.NET MVC內置的ControllerFactory-----DefaultControllerFactory
在ASP.NET MVC框架中已經給我們提供了內置的ControllerFactory,即DefaultControllerFactory。它首先從routing data中獲取到所請求的controller的名字,然后根據該名字去尋找相應的Controller。如果你希望一個類能被ControllerFactory當作Controller並生成需要遵循以下規則:
(1)該類的作用域必須為public
(2)該類必須可被實例化
(3)該類不能是泛型類
(4)該類的名稱的結尾必須是Controller (這也是我們常說的約定大於配置)
(5)該類必須實現IController接口
利用DefaultControllerFactory指定命名空間優先級
如果我們希望DefaultControllerFactory在尋找Controller時都優先在指定的命名空間下尋找,我們可以利用它的DefaultNamespaces屬性。不多說,看代碼就明白了:
public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { AreaRegistration.RegisterAllAreas(); WebApiConfig.Register(GlobalConfiguration.Configuration); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); ControllerBuilder.Current.DefaultNamespaces.Add("MyNamespace"); } }
我們在Global.asax.cs中的Application_Start方法中添加最后一句代碼,ControllerBuilder.Current屬性返回的是當前的ControllerFactory(在這里就DefaultControllerFactory實例)。這樣,DefaultControllerFactroy在尋找相應的Controller都優先在MyNamespace空間下尋找。如果在MyNamespace空間未找到,則繼續在其他命名空間尋找。
2.使用自定義ControllerFactory
如果ASP.NET MVC內置的DefaultControllerFactory無法滿足需求的話,我們可以自定義ControllerFactory來替代DefaultControllerFactory。
首先,一個ControllerFactory需要實現IControllerFactory接口:
public interface IControllerFactory { IController CreateController(RequestContext requestContext, string controllerName); SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, string controllerName); void ReleaseController(IController controller); }
其中CreateController方法是關鍵,它定義了一個ControllerFactory是如何根據信息尋找相應的Controller。而GetControllerSessionBehavior定義指定Controller的Session行為,ReleaseController 方法則是釋放指定Controller。
下面來看一個例子吧:
public class CustomControllerFactory : IControllerFactory { public IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName) { //在這里,為了簡單,我不管當前http請求信息是什么,都生成HomeController實例。 Type targetType = typeof(HomeController); return (IController)DependencyResolver.Current.GetService(targetType); } public System.Web.SessionState.SessionStateBehavior GetControllerSessionBehavior(System.Web.Routing.RequestContext requestContext, string controllerName) { //默認的Session行為 return SessionStateBehavior.Default; } public void ReleaseController(IController controller) { IDisposable disposable = controller as IDisposable; if (disposable != null) { disposable.Dispose(); } } }
在這個例子,不管http請求的信息是什么CustomControllerFactory都生成HomeController實例。
接着我們需要在Global.asax.cs的Application_Start方法中注冊我們自定義的CustomControllerFactory:
public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { AreaRegistration.RegisterAllAreas(); WebApiConfig.Register(GlobalConfiguration.Configuration); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes);
//注冊自定義ControllerFactory ControllerBuilder.Current.SetControllerFactory(new CustomControllerFactory()); } }
現在,MVC使用的就是我們自定義的ControllerFactory了:無論請求信息是什么,生成的都是HomeController。