上面这张图是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
。