#asp.net-mvc #asp.net-mvc-3
#asp.net-mvc #asp.net-mvc-3
Вопрос:
Удивлен, что я нигде не нахожу этот ответ, как я могу определить, какой контроллер / действие будет вызвано для данного URL в MVC 3?
Обновить
Что я действительно хочу знать: «как я могу определить, какое ControllerAction будет вызвано для данного URL в MVC 3?»…. да
Итак, либо я не знаю о волшебном методе, который это делает:
ControllerActionInfo GetControllerActionInfo(string url)
Или мне придется создать его самому, выполняя все, что делает MVC, когда получает http-запрос.
Моя цель спросить об этом в StackOverflow заключается в том, что я могу сэкономить некоторое время на обратном проектировании этого поведения. Правильный ответ должен напоминать:
Here's how you can do it:
и последует некоторый код.
Комментарии:
1. Мне было бы интересно узнать вариант использования для этого. Обычно из приложения вы создаете URL-адрес из контроллера / действия и позволяете платформе обрабатывать маршрутизацию. Зачем вам нужно делать обратное?
2. Вариант использования является совершенно секретным defcon 5.
3. Тогда ответ заключается в переборе набора маршрутов, пока вы не найдете первый, который соответствует HttpContext для данного URL. Способ сделать это засекречен совершенно, совершенно секретно. 🙂 Или вы могли бы посмотреть в исходном коде, aspnet.codeplex.com . Я бы не ожидал, что фреймворк предоставит это, и я не думаю, что это так.
4. Да, я мог бы покопаться в источнике. Даже если бы у меня не было исходного кода, я мог бы декомпилировать. И то же самое мог бы сделать каждый человек, который когда-либо задавал вопрос о переполнении стека.
Ответ №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. Спасибо. Я думаю, что это намного ближе к тому, что мне нужно. Но как насчет того, чтобы знать, какое действие будет выполнено?
Ответ №2:
Логика для этого находится в System.Web.Mvc.MvcHandler
классе, System.Web.Mvc.DefaultControllerFactory
class и System.Web.Mvc.ControllerActionInvoker
classе. .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
,,,,,,,.- Если вы хотите лучше понять, как работает маршрутизация в MVC, я бы настоятельно рекомендовал статью Скотта Гу о маршрутизации MVC.
Комментарии:
1. .net reflector больше не мой друг. Telerik JustDecompile — мой новый друг.
2. Этот ответ на самом деле не отвечает на вопрос. Это просто своего рода сообщает, что происходит, учитывая МАРШРУТ по УМОЛЧАНИЮ, который используется в проекте mvc.
3. @RonnieOverby, ваш вопрос касался маршрутизации MVC. Если вам нужна дополнительная информация конкретно о маршрутизации MVC, вам следует проверить ссылку Скотта Гу в конце моего ответа. Если ваш вопрос касается того, как работает маршрутизация Microsoft в целом, то вам следует указать это. Мой ответ иллюстрирует используемый шаблон и то, как он применяется по умолчанию в MVC. Я не уверен, что еще вы хотите
4. @RonnieOverby, возможно, вы захотите ознакомиться с этой статьей 4guysfromrolla, используя ASP.NET Маршрутизация без ASP.NET MVC за помощью в понимании основ ASP.NET маршрутизация, независимо от ASP.NET Платформа MVC . Единственное конкретное отличие маршрутизации в целом от маршрутизации MVC заключается в том, что MVC выдаст исключение, если
{controller}
и{action}
параметры маршрута не определены. (Они могут быть определены неявно, установив значение по умолчанию)