此文摘要小妞之路,记录一下,方便自己查看学习
Controller Factory控制器工厂:
一般在实际项目中的用法:使用内置的Controller Factory,叫 DefaultControllerFactory。
当 DefaultControllerFactory 类接收到一个 controller 实例的请求时,在 DefaultControllerFactory 类内部通过 GetControllerType 方法来获得 controller 的类型,然后把这个类型传递给 GetControllerInstance 方法以获得 controller 的实例。
所以在 GetControllerInstance 方法中就需要有某个东西来创建 controller 实例,这个创建的过程就是 controller 被激活的过程。
默认情况下 MVC 使用 DefaultControllerActivator 类来做 controller 的激活工作,它实现了 IControllerActivator 接口,该接口定义如下:
public interface IControllerActivator { IController Create(RequestContext requestContext, Type controllerType); }
内置的Action Invoker (ControllerActionInvoker)寻找的是和请求的 action 名称相同的 action 方法。比如路由系统提供的 action 值是 Index,那么 ControllerActionInvoker 将寻找一个名为 Index 的方法,如果找到了,它就用这个方法来处理请求。ControllerActionInvoker 允许我们对此行为进行调整,即可以通过使用 ActionName 特性对 action 使用别名,如下对 CustomerController 的 List action 方法使用 ActionName 特性:
public class CustomerController : Controller {
...
[ActionName("Enumerate")]
public ViewResult List() {
return View("Result", new Result {
ControllerName = "Customer",
ActionName = "List"
});
}
}
当请求 Enumerate Action 时,将会使用 List 方法来处理请求。下面是请求 /Customer/Enumerate 的结果:
这时候对 /Customer/List 的请求则会无效,报“找不到资源”的错误,如下:
使用 Action 方法别名有两个好处:一是可以使用非法的C#方法名来作为请求的 action 名,如 [ActionName("User-Registration")]。二是,如果你有两个功能不同的方法,有相同的参数相同的名称,但针对不同的HTTP请求(一个使用 [HttpGet],另一个使用 [HttpPost]),你可以给这两个方法不同的方法名,然后使用 [ActionName] 来指定相同的 action 请求名称。
加一个LocalIndex 方法,并对它应用 “Index”别名,代码如下:
public class CustomerController : Controller { public ViewResult Index() { return View("Result", new Result { ControllerName = "Customer", ActionName = "Index" }); } [ActionName("Index")] public ViewResult LocalIndex() { return View("Result", new Result { ControllerName = "Customer", ActionName = "LocalIndex" }); }
这时如果请求 /Customer/Index,这两个 action 方法都会被匹配到而引发歧义问题,程序将会报错:
我们来考虑这样一种情况:
所有的 action 选择器都继承自 ActionMethodSelectorAttribute 类,这个类的定义如下:
using System.Reflection; namespace System.Web.Mvc { [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)] public abstract class ActionMethodSelectorAttribute : Attribute { public abstract bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo); } }
同一个URL请求,在本地和远程请求的是不同的 action (如对于本地则绕过权限验证可能需要这么做)。那么自定义一个本地的 Action 选择器会是一个不错的选择。下面我们来实现这样一个功能的 Action 选择器:
using System.Reflection; using System.Web.Mvc; namespace MvcApplication2.Infrastructure { public class LocalsAttribute : ActionMethodSelectorAttribute { public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo) { return controllerContext.HttpContext.Request.IsLocal; } } }
这时候我们再对 LocalIndex 应用我们自定义的 Local 选择器:
...
[Locals]//这样两个action名字相同时访问就不会有歧义了
[ActionName("Index")]
public ViewResult LocalIndex() {
return View("Result", new Result {
ControllerName = "Customer",
ActionName = "Index"
});
}
...