我已经离开了MVC请求生命周期,但我仍然没有清楚根据注册路由将请求路由到处理程序的位置。
我们使用url放置MVC请求,然后找到控制器并提供正确的cshtml页面。 由于url没有任何资源类型,http模块事件或http处理程序如何区分MVC请求并将其传递给正确的控制器。
答案 0 :(得分:4)
您有来自Microsoft的ASP .Net站点的this document,详细描述了MVC 5请求生命周期以及它如何集成到ASP .Net生命周期中。 pdf中的图表的某些部分链接到msdn中的相关页面。
来自Lukasz Lysic的另一个好资源是this set of slides,它详细解释了MVC 4中的请求生命周期。
编辑:我不喜欢仅限链接的答案,所以我在下面添加了更多详细信息。
在您的机器级别web.config上,您会看到注册为UrlRoutingModule
的IHttpModule
。例如,在我的电脑上我有:
<system.web>
<httpModules>
...
<add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" />
...
</httpModules>
<system.web>
在PostResolveRequestCache
应用程序事件中,路由模块遍历RouteCollection
属性中的所有路由,并搜索具有与HTTP请求格式匹配的URL模式的路由。当模块找到匹配的路由时,它会检索该路由的IRouteHandler
对象。从路由处理程序,模块获取一个IHttpHandler
对象,并将其用作当前请求的HTTP处理程序(调用其ProcessRequest
方法或其异步对应方BeginProcessRequest
和EndProcessRequest
)。
对于MVC应用程序,当您使用global.asax
扩展方法在MapRoute
中添加路由时,会创建MVCRouteHandler
。
检查RouteCollectionExtensions
类中的MapRoute
方法:
public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces)
{
if (routes == null)
{
throw new ArgumentNullException("routes");
}
if (url == null)
{
throw new ArgumentNullException("url");
}
Route route = new Route(url, new MvcRouteHandler())
{
Defaults = CreateRouteValueDictionaryUncached(defaults),
Constraints = CreateRouteValueDictionaryUncached(constraints),
DataTokens = new RouteValueDictionary()
};
ConstraintValidation.Validate(route);
if ((namespaces != null) && (namespaces.Length > 0))
{
route.DataTokens[RouteDataTokenKeys.Namespaces] = namespaces;
}
routes.Add(name, route);
return route;
}
因此,当请求与MVC路由匹配时,它将由MvcRouteHandler
处理。如上所述,路由IRouteHandler
的目的是获取应用程序将继续处理请求的IHttpHandler
。 MvcRouteHandler
将返回MvcHandler
,这是MVC特定管道的入口点。
检查MvcRouteHandler
类的GetHttpHandler
方法:
protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext)
{
requestContext.HttpContext.SetSessionStateBehavior(GetSessionStateBehavior(requestContext));
return new MvcHandler(requestContext);
}
MVC特定的管道基本上以ProcessRequest
方法(或异步BeginProcessRequest
/ EndProcessRequest
)开头。 MvcHandler
将获得IControllerFactory
(默认情况下,将使用DefaultControllerFactory
,除非您在global.asax Application_Start中使用ControllerBuilder.Current.SetDefaultControllerFactory
注册自己的,使用它来创建控制器实例基于当前路由值并启动控制器执行。
检查MvcHandler
类的ProcessRequest
方法:
protected internal virtual void ProcessRequest(HttpContextBase httpContext)
{
IController controller;
IControllerFactory factory;
ProcessRequestInit(httpContext, out controller, out factory);
try
{
controller.Execute(RequestContext);
}
finally
{
factory.ReleaseController(controller);
}
}
private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory)
{
// If request validation has already been enabled, make it lazy. This allows attributes like [HttpPost] (which looks
// at Request.Form) to work correctly without triggering full validation.
// Tolerate null HttpContext for testing.
HttpContext currentContext = HttpContext.Current;
if (currentContext != null)
{
bool? isRequestValidationEnabled = ValidationUtility.IsValidationEnabled(currentContext);
if (isRequestValidationEnabled == true)
{
ValidationUtility.EnableDynamicValidation(currentContext);
}
}
AddVersionHeader(httpContext);
RemoveOptionalRoutingParameters();
// Get the controller type
string controllerName = RequestContext.RouteData.GetRequiredString("controller");
// Instantiate the controller and call Execute
factory = ControllerBuilder.GetControllerFactory();
controller = factory.CreateController(RequestContext, controllerName);
if (controller == null)
{
throw new InvalidOperationException(
String.Format(
CultureInfo.CurrentCulture,
MvcResources.ControllerBuilder_FactoryReturnedNull,
factory.GetType(),
controllerName));
}
}
这应解释传入请求如何与MVC中的控制器匹配。对于MVC管道的其余部分,请检查帖子开头的链接!