【问题标题】:In which request event does MVC Routing occurs.MVC 路由发生在哪个请求事件中。
【发布时间】:2014-04-26 09:02:52
【问题描述】:

我已经完成了 MVC 请求生命周期,但我仍然不清楚根据注册路由将请求路由到处理程序的位置。

我们使用 url 放置 MVC 请求,然后它会找到控制器并提供正确的 cshtml 页面。 由于 url 没有任何资源类型,http 模块事件或 http 处理程序如何区分 MVC 请求并将其传递给正确的控制器。

【问题讨论】:

  • 用谷歌搜索 MVC 管道。例如,来自 ASP .Net 站点的this document 描述了 MVC 5 管道。或者这个 set of slides 描述 MVC 4
  • @DanielJ.G.谢谢,MVC 4 的幻灯片非常详细,谢谢。你能在答案部分写下这个标记为答案吗?
  • 我不认为它本身是一个请求事件。您可能在询问 HttpApplication 实例上的事件。如果我错了,请纠正我。
  • @deostroll danny 提供的链接(“幻灯片集”)回答了 http 模块中路由处理程序是如何完成的,回答了我的说明。
  • 是的,我同意这个答案。您特别感兴趣的事件是发生在 HttpApplication 实例上的 PostRequestResolveCache。这是 UrlRoutingModule 完成大部分工作的地方。

标签: asp.net-mvc http asp.net-mvc-routing httphandler


【解决方案1】:

您有来自 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 方法或其异步对应方法 BeginProcessRequestEndProcessRequest)。

  • 您可以在 Microsoft .Net 参考源站点上查看 UrlRoutingModule 代码 here

对于 MVC 应用程序,当您使用 MapRoute 扩展方法在 global.asax 中添加路由时,会创建一个 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,应用程序将使用该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 管道的其余部分,请查看文章开头的链接!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-02-12
    • 1970-01-01
    • 2019-10-29
    • 2015-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-15
    相关资源
    最近更新 更多