我很惊讶我没有在任何地方找到这个答案,我怎样才能确定在MVC 3中为给定的URL调用哪个Controller / Action?
我真正想知道的是: "如何确定在MVC 3中为给定的URL调用哪个ControllerAction?" ....耶
所以,要么我不知道这样做的神奇方法:
ControllerActionInfo GetControllerActionInfo(string url)
或者,我必须自己创建它,无论MVC在收到http请求时做什么。
我在StackOverflow上询问此问题的目的是我可以节省一些时间逆向工程这种行为。正确的答案应该类似于:
Here's how you can do it:
后面会有一些代码。
答案 0 :(得分:1)
您必须使用虚拟HttpContext和HttpRequest类,如下所示:
public class DummyHttpRequest : HttpRequestBase {
private string mUrl;
public DummyHttpRequest(string url) {
mUrl = url;
}
public override string AppRelativeCurrentExecutionFilePath {
get {
return mUrl;
}
}
public override string PathInfo {
get {
return string.Empty;
}
}
}
public class DummyHttpContext : HttpContextBase {
private string mUrl;
public DummyHttpContext(string url) {
mUrl = url;
}
public override HttpRequestBase Request {
get {
return new DummyHttpRequest(mUrl);
}
}
}
修改此外,您可以扩展DefaultControllerFactory
并添加一个简单的方法来获取所需的信息,而不是Controller
的实例。 (注意:这只是一个示例,您必须支持其他方面,如ActionNameAttribute
等)
public class ControllerActionInfo {
public ControllerActionInfo(Type controllerType, MethodInfo action) {
ControllerType = controllerType;
Action = action;
}
public Type ControllerType { get; private set; }
public MethodInfo Action { get; private set; }
}
public class DefaultControllerFactoryEx : DefaultControllerFactory {
public ControllerActionInfo GetInfo(RequestContext requestContext, string controllerName) {
Type controllerType = GetControllerType(requestContext, controllerName);
if (controllerType == null) {
return null;
}
MethodInfo actionMethod = controllerType.GetMethod(requestContext.RouteData.GetRequiredString("action"), BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Public);
return new ControllerActionInfo(controllerType, actionMethod);
}
}
然后,使用以下代码段来访问控制器:
DummyHttpContext httpContext = new DummyHttpContext("~/home/index");
RouteData routeData = RouteTable.Routes.GetRouteData(httpContext);
// IController controller = new DefaultControllerFactory().CreateController(new RequestContext(httpContext, routeData), routeData.GetRequiredString("controller"));
DefaultControllerFactoryEx controllerFactory = new DefaultControllerFactoryEx();
var result = controllerFactory.GetInfo(new RequestContext(httpContext, routeData), routeData.GetRequiredString("controller"));
答案 1 :(得分:0)
这个逻辑在System.Web.Mvc.MvcHandler
类,System.Web.Mvc.DefaultControllerFactory
类和System.Web.Mvc.ControllerActionInvoker
类中。 .NET Reflector是你的朋友。
基本上,MVC框架:
使用反射来获取应用程序项目中的所有控制器。
然后它会像IEnumerable<string> controllerNames = controllerTypes.Select(controllerType => controllerType.Name.Replace("Controller",string.Empty));
那样。然后,它尝试将第一个路径段{controller}
与这些已清理的控制器类型名称之一(不区分大小写)进行匹配。
然后,它会查看此控制器的公共方法,这些方法的返回类型为ActionResult
或某种派生类型。它将方法名称与第二个路径段{action}
匹配,作为要调用的操作方法。
如果所选方法的参数名为id
,则它将第三个路径段{id}
与该值匹配,并将其传递给方法。否则,将忽略可选的id
参数。
如果返回的ActionResult
类型是ViewResultBase
的衍生物,那么IViewEngine
会尝试使用为此指定的任何约定来查找项目中的相应视图查看引擎。例如,WebFormViewEngine
默认会在项目中查找~/Views/{controller}/{action}.ascx
,~/Views/{controller}/{action}.aspx
,~/Views/Shared/{action}.ascx
,~/Views/Shared/{action}.aspx
。