asp.net mvc Controller Factory

此文摘要小妞之路,记录一下,方便自己查看学习

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"
    });
}
...
原文地址:https://www.cnblogs.com/wuyiran/p/6068557.html