zoukankan      html  css  js  c++  java
  • MVC源码分析

    上一篇 说到了路由事件注册以及路由表的生成, 前面 也解析到了, 管道事件的建立, 那么接下来, 肯定就是要调用执行这些事件了, 这些就不表了, 我已经得到我想要的部分了, 接下来, 在执行这些管道事件的时候, 肯定就会执行到之前 UrlRoutingModule注册的方法. 接下来, 就看一下, 这个事件干了些什么. 

    一、OnApplicationPostResolveRequestCache 方法

    private void OnApplicationPostResolveRequestCache(object sender, EventArgs e)
    {
        HttpApplication application = (HttpApplication) sender;
        HttpContextBase context = new HttpContextWrapper(application.Context);
        this.PostResolveRequestCache(context);
    }

    这里调用了自己(UrlRoutingModule)的 PostResolveRequestCache 方法. 

    public virtual void PostResolveRequestCache(HttpContextBase context)
    {
       //根据http上下文去 之前生成的路由表中查找匹配的路由 RouteData routeData = this.RouteCollection.GetRouteData(context); if (routeData != null) {
         //这里返回的 IRouteHandler 其实就是 MvcRouteHandler(上一篇)有提到过
         //这个MvcRouteHandler中, 就有一个方法, 用来返回 IHttpHander的, 其实就是返回的 MvcHandler
    IRouteHandler routeHandler = routeData.RouteHandler; if (routeHandler == null) { throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture,
               SR.GetString("UrlRoutingModule_NoRouteHandler"), new object[0])); }
         //在注册路由的时候, Ignore方式注册的, 会返回StopRoutingHandler if (!(routeHandler is StopRoutingHandler)) {
           //在这里, 首先创建了请求上下文 RequestContext requestContext = new RequestContext(context, routeData); context.Request.RequestContext = requestContext;
            //在这里获取到MVC的处理接口, 就是 MvcHandler IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext); if (httpHandler == null) { throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture,
                 SR.GetString("UrlRoutingModule_NoHttpHandler"), new object[] { routeHandler.GetType() })); } if (httpHandler is UrlAuthFailureHandler) { if (!FormsAuthenticationModule.FormsAuthRequired) { throw new HttpException(0x191, SR.GetString("Assess_Denied_Description3")); } UrlAuthorizationModule.ReportUrlAuthorizationFailure(HttpContext.Current, this); } else {
              //将 MvcHandler 存入 HttpContext 对象的 _remapHandler 属性中 context.RemapHandler(httpHandler); } } } }

     按照顺序, 看上面我标红的接个方法.

    1. GetRouteData()方法

    //RouteCollection
    public
    RouteData GetRouteData(HttpContextBase httpContext) { if (httpContext == null) { throw new ArgumentNullException("httpContext"); } if (httpContext.Request == null) { throw new ArgumentException(SR.GetString("RouteTable_ContextMissingRequest"), "httpContext"); } if (base.Count != 0) { bool flag = false; bool flag2 = false; if (!this.RouteExistingFiles) { flag = this.IsRouteToExistingFile(httpContext); flag2 = true; if (flag) { return null; } } using (this.GetReadLock()) { foreach (RouteBase base2 in this) { RouteData routeData = base2.GetRouteData(httpContext); if (routeData != null) { if (!base2.RouteExistingFiles) { if (!flag2) { flag = this.IsRouteToExistingFile(httpContext); flag2 = true; } if (flag) { return null; } } return routeData; } } } } return null; }

    接着看, 这里调用了 Route 类的 GetRouteData() 方法

    public override RouteData GetRouteData(HttpContextBase httpContext)
    {
        string virtualPath = httpContext.Request.AppRelativeCurrentExecutionFilePath.Substring(2) + httpContext.Request.PathInfo;
        RouteValueDictionary values = this._parsedRoute.Match(virtualPath, this.Defaults);
        if (values == null)
        {
            return null;
        }
        RouteData data = new RouteData(this, this.RouteHandler);
        if (!this.ProcessConstraints(httpContext, values, RouteDirection.IncomingRequest))
        {
            return null;
        }
        foreach (KeyValuePair<string, object> pair in values)
        {
            data.Values.Add(pair.Key, pair.Value);
        }
        if (this.DataTokens != null)
        {
            foreach (KeyValuePair<string, object> pair2 in this.DataTokens)
            {
                data.DataTokens[pair2.Key] = pair2.Value;
            }
        }
        return data;
    }

    这里就会根据之前注册路由的限制条件去匹配路由了. 将最后匹配到的那个路由返回.

    2. GetHttpHandler()方法

    这里会调用 MvcRouteHandler 的 GetHttpHandler 方法, 前面篇章提过的.

    protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext)
    {
        requestContext.HttpContext.SetSessionStateBehavior(this.GetSessionStateBehavior(requestContext));
        return new MvcHandler(requestContext);
    }

    返回一个 MvcHandler .

    3. RemapHandler()方法

    这里会调用 HttpContext 的RemapHandler 方法.

    public void RemapHandler(IHttpHandler handler)
    {
        this.EnsureHasNotTransitionedToWebSocket();
        IIS7WorkerRequest request = this._wr as IIS7WorkerRequest;
        if (request != null)
        {
            if (this._notificationContext.CurrentNotification >= RequestNotification.MapRequestHandler)
            {
                throw new InvalidOperationException(SR.GetString("Invoke_before_pipeline_event",
             new object[] { "HttpContext.RemapHandler", "HttpApplication.MapRequestHandler" })); } string handlerType = null; string handlerName = null; if (handler != null) { Type type = handler.GetType(); handlerType = type.AssemblyQualifiedName; handlerName = type.FullName; } request.SetRemapHandler(handlerType, handlerName); } this._remapHandler = handler; }

    这里主要就是看最后一句了, 将 mvchandler存入到 HttpContext._remapHandler 中

    到这里, 其实就能看到 路由匹配的过程以及获取到 mvc处理程序(这个是入口). 

    二、路由匹配

    在分析路由的时候, 可以借助一个插件 : RouteDebugger, 获取方式为, 在vs程序包控制台中, 执行以下命令

    PM> Install-Package routedebugger

    添加完之后, 程序会自动在web.config中添加如下配置:

    <add key="RouteDebugger:Enabled" value="true" />

    我们只需要直接运行程序就好了. 先看一张效果图:

    在图上, 能清晰的看到, 匹配过程中, 与其中的哪一个路由能匹配的上. 哪一些不能匹配上.

    两个小问题:

      如果有两个匹配规则相同, 但是路由名不同的, 会匹配上哪一个呢?

        哪一个在前面注册的, 就回匹配到哪一个, 后面的不会继续匹配.

      那会不会有匹配规则不同, 但是路由名相同的呢?

        一般在使用key的时候, 都是要保证key的唯一性, 路由同样如此, 路由名不能重复, 必须唯一, 否则会报错.

    有兴趣的朋友, 可以去了解下

    目录已同步

  • 相关阅读:
    HDU--1212大数取模
    欧拉函数
    自制体重转换器
    常用快捷键
    Markdown基本语法
    python全栈开发day50-jquery之ajax、XmlHttpRquest
    python全栈开发day49-jquery的位置信息、事件流、事件对象,事件委托,事件绑定和解绑
    阳历转阴历算法
    python全栈开发day48-jqurey自定义动画,jQuery属性操作,jQuery的文档操作,jQuery中的ajax
    python全栈开发day47-jqurey
  • 原文地址:https://www.cnblogs.com/elvinle/p/6278038.html
Copyright © 2011-2022 走看看