zoukankan      html  css  js  c++  java
  • ASP.NET请求过程-从源码角度研究MVC路由、Handler、控制器

    路由常用对象

    RouteBase

    用作表示 ASP.NET 路由的所有类的基类。        就是路由的一个基础抽象类。

    //
    // 摘要:
    //     用作表示 ASP.NET 路由的所有类的基类。
    [TypeForwardedFrom("System.Web.Routing, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")]
    public abstract class RouteBase
    {
        //
        // 摘要:
        //     初始化该类供继承的类实例使用。此构造函数只能由继承的类调用。
        protected RouteBase();
    
        //
        // 摘要:
        //     获取或设置一个值,该值指示 ASP.NET 路由操作是否应处理与现有文件匹配的 URL。
        //
        // 返回结果:
        //     如果 ASP.NET 路由操作处理所有请求(甚至包括与现有文件匹配的请求),则为 true;否则为 false。默认值为 false。
        public bool RouteExistingFiles { get; set; }
    
        //
        // 摘要:
        //     当在派生类中重写时,会返回有关请求的路由信息。
        //
        // 参数:
        //   httpContext:
        //     一个对象,封装有关 HTTP 请求的信息。
        //
        // 返回结果:
        //     一个对象,包含路由定义的值(如果该路由与当前请求匹配)或 null(如果该路由与请求不匹配)。
        public abstract RouteData GetRouteData(HttpContextBase httpContext);
        //
        // 摘要:
        //     当在派生类中重写时,会检查路由是否与指定值匹配,如果匹配,则生成一个 URL,然后检索有关该路由的信息。
        //
        // 参数:
        //   requestContext:
        //     一个对象,封装有关所请求的路由的信息。
        //
        //   values:
        //     一个包含路由参数的对象。
        //
        // 返回结果:
        //     一个对象(包含生成的 URL 和有关路由的信息)或 null(如果路由与 values 不匹配)。
        public abstract VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values);
    }
    View Code

    是一个抽象类,里面两个抽象方法。(一般抽象类,抽象方法,虚方法  都是为了扩展用的           MVC最大的特点就是扩展,     1自身从原有的框架里面扩展来得。 2本身各个方面又支持扩展  )

    Route

    提供用于定义路由及获取路由相关信息的属性和方法。       他继承了RouteBase。

    public class Route : RouteBase

    1、构造函数 

    //
    // 摘要:
    //     使用指定的 URL 模式和处理程序类初始化 System.Web.Routing.Route 类的新实例。
    //
    // 参数:
    //   url:
    //     路由的 URL 模式。
    //
    //   routeHandler:
    //     处理路由请求的对象。
    public Route(string url, IRouteHandler routeHandler);
    //
    // 摘要:
    //     使用指定的 URL 模式、默认参数值和处理程序类初始化 System.Web.Routing.Route 类的新实例。
    //
    // 参数:
    //   url:
    //     路由的 URL 模式。
    //
    //   defaults:
    //     用于 URL 中缺失的任何参数的值。
    //
    //   routeHandler:
    //     处理路由请求的对象。
    public Route(string url, RouteValueDictionary defaults, IRouteHandler routeHandler);
    //
    // 摘要:
    //     使用指定的 URL 模式、默认参数值、约束和处理程序类初始化 System.Web.Routing.Route 类的新实例。
    //
    // 参数:
    //   url:
    //     路由的 URL 模式。
    //
    //   defaults:
    //     要在 URL 不包含所有参数时使用的值。
    //
    //   constraints:
    //     一个用于指定 URL 参数的有效值的正则表达式。
    //
    //   routeHandler:
    //     处理路由请求的对象。
    public Route(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, IRouteHandler routeHandler);
    //
    // 摘要:
    //     使用指定的 URL 模式、默认参数值、约束、自定义值和处理程序类初始化 System.Web.Routing.Route 类的新实例。
    //
    // 参数:
    //   url:
    //     路由的 URL 模式。
    //
    //   defaults:
    //     要在 URL 不包含所有参数时使用的值。
    //
    //   constraints:
    //     一个用于指定 URL 参数的有效值的正则表达式。
    //
    //   dataTokens:
    //     传递到路由处理程序但未用于确定该路由是否匹配特定 URL 模式的自定义值。这些值会传递到路由处理程序,以便用于处理请求。
    //
    //   routeHandler:
    //     处理路由请求的对象。
    public Route(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, RouteValueDictionary dataTokens, IRouteHandler
    routeHandler);
    View Code

    url: 用于匹配路由和 URL 的模式。  ——就对应我们mvc中路由定义的url

    defaults:他的类型为RouteValueDictionary,就是把Dictionary字典封装了一下。  ——就对应我们MVC中路由定义的defaults。但是mvc中的defaults是object类型的 (new { controller = "Home", action = "Index", id = UrlParameter.Optional }) ,源码中做了一次转化

        private static RouteValueDictionary CreateRouteValueDictionaryUncached(object values)
        {
            IDictionary<string, object> dictionary = values as IDictionary<string, object>;
            if (dictionary != null)
            {
                return new RouteValueDictionary(dictionary);
            }
            return TypeHelper.ObjectToDictionaryUncached(values);
        }
    MVC中路由default转化成Route中default

    routeHandler:这个比较重要类型为 IRouteHandler  它就是mvc中管道模型的handler。从这里看出mvc中的handler是从路由中注册进去的。这个下面讲到handler的时候在详细讲解。

    constraints:他的类型类型为RouteValueDictionary,一个用于指定 URL 参数的有效值的正则表达式。  ——就适应我们MVC中的的constraints但是mvc中的是一个object类型(new { controller = "^H.*", action = "^Index$|^About$"},)源码中也做了一次转化,和defaults的转化方法是同一个。

    dataTokens:他的类型也是RouteValueDictionary,定义:传递到路由处理程序但未用于确定该路由是否匹配特定 URL 模式的自定义值。这些值会传递到路由处理程序,以便用于处理请求。   这个直接上图其实就是MVC中的namespace(new[] { "URLsAndRoutes.AdditionalControllers" })  命名空间就是非主流。  这个直接上图。

    下面使我们MVC中路由定义。

    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    
        //忽略Hand控制器下面的所有请求 不通过路由解析
        routes.IgnoreRoute("Hand/{*pathInfo}");
    
        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );
    }

    2、属性

    //
    // 摘要:
    //     获取或设置为 URL 参数指定有效值的表达式的词典。
    //
    // 返回结果:
    //     一个包含参数名称和表达式的对象。
    public RouteValueDictionary Constraints { get; set; }
    //
    // 摘要:
    //     获取或设置传递到路由处理程序但未用于确定该路由是否匹配 URL 模式的自定义值。
    //
    // 返回结果:
    //     一个包含自定义值的对象。
    public RouteValueDictionary DataTokens { get; set; }
    //
    // 摘要:
    //     获取或设置要在 URL 不包含所有参数时使用的值。
    //
    // 返回结果:
    //     一个包含参数名称和默认值的对象。
    public RouteValueDictionary Defaults { get; set; }
    //
    // 摘要:
    //     获取或设置处理路由请求的对象。
    //
    // 返回结果:
    //     处理请求的对象。
    public IRouteHandler RouteHandler { get; set; }
    //
    // 摘要:
    //     获取或设置路由的 URL 模式。
    //
    // 返回结果:
    //     用于匹配路由和 URL 的模式。
    //
    // 异常:
    //   T:System.ArgumentException:
    //     以下任一值:以 ~ 或 / 开头的值。包含 ? 字符的值。“全部捕捉”参数不在末尾。
    //
    //   T:System.Exception:
    //     没有使用分隔符或文字常量分隔 URL 分段。
    public string Url { get; set; }
    View Code

    这些属性都在构造函数中讲了。

    3、方法

    //
    // 摘要:
    //     返回有关所请求路由的信息。
    //
    // 参数:
    //   httpContext:
    //     一个对象,封装有关 HTTP 请求的信息。
    //
    // 返回结果:
    //     一个对象,其中包含路由定义中的值。
    public override RouteData GetRouteData(HttpContextBase httpContext);
    //
    // 摘要:
    //     返回与路由关联的 URL 的相关信息。
    //
    // 参数:
    //   requestContext:
    //     一个对象,封装有关所请求的路由的信息。
    //
    //   values:
    //     一个包含路由参数的对象。
    //
    // 返回结果:
    //     一个包含与路由关联的 URL 的相关信息的对象。
    public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values);
    //
    // 摘要:
    //     确定参数值是否与该参数的约束匹配。
    //
    // 参数:
    //   httpContext:
    //     一个对象,封装有关 HTTP 请求的信息。
    //
    //   constraint:
    //     用于测试 parameterName 的正则表达式或对象。
    //
    //   parameterName:
    //     要测试的参数的名称。
    //
    //   values:
    //     要测试的值。
    //
    //   routeDirection:
    //     一个指定 URL 路由是否处理传入请求或构造 URL 的值。
    //
    // 返回结果:
    //     如果参数值与约束匹配,则为 true;否则为 false。
    //
    // 异常:
    //   T:System.InvalidOperationException:
    //     constraint 不是包含正则表达式的字符串。
    protected virtual bool ProcessConstraint(HttpContextBase httpContext, object constraint, string parameterName, RouteValueDictionary values,
    RouteDirection routeDirection);
    View Code

    两个从父类RouteBase中抽象实现的。两外一个虚方法。(虚方法好呀,可以扩展)

     public override RouteData GetRouteData(HttpContextBase httpContext);

    返回有关所请求路由的信息。这个RouteData就是在MVC控制器中的RouteData,参数HttpContextBase也是MVC控制器中的HttpContext。下面是源码,就是创建一个RouteData然后把Route的信息赋值给他。

     

    public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values);

     返回与路由关联的 URL 的相关信息。

    //
    // 摘要:
    //     表示有关路由和虚拟路径的信息,该路由和虚拟路径是在使用 ASP.NET 路由框架生成 URL 时产生的。
    [TypeForwardedFrom("System.Web.Routing, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")]
    public class VirtualPathData
    {
        //
        // 摘要:
        //     初始化 System.Web.Routing.VirtualPathData 类的新实例。
        //
        // 参数:
        //   route:
        //     用于生成 URL 的对象。
        //
        //   virtualPath:
        //     生成的 URL。
        public VirtualPathData(RouteBase route, string virtualPath);
    
        //
        // 摘要:
        //     获取路由定义的自定义值集合。
        //
        // 返回结果:
        //     路由的自定义值集合。
        public RouteValueDictionary DataTokens { get; }
        //
        // 摘要:
        //     获取或设置用于创建 URL 的路由。
        //
        // 返回结果:
        //     一个对象,该对象表示与用于生成 URL 的参数匹配的路由。
        public RouteBase Route { get; set; }
        //
        // 摘要:
        //     获取或设置依据路由定义创建的 URL。
        //
        // 返回结果:
        //     依据路由生成的 URL。
        public string VirtualPath { get; set; }
    }
    VirtualPathData

    参数RequestContext 这个就是HttpContext.Request.RequestContext

    protected virtual bool ProcessConstraint(HttpContextBase httpContext, object constraint, string parameterName, RouteValueDictionary values, RouteDirection routeDirection);

    确定参数值是否与该参数的约束匹配。

    下图中画圈的  是   定义类必须实现才能检查某 URL 参数值是否对约束有效的协定。  他是一个接口

    这个接口的实现有一下几个

     以FloatRouteConstraint为例。其实主要做的是正则表达式验证,以及类型TryPase转化测试。

    public class FloatRouteConstraint : IRouteConstraint
        {
            public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
            {
                if (parameterName == null)
                {
                    throw Error.ArgumentNull("parameterName");
                }
                if (values == null)
                {
                    throw Error.ArgumentNull("values");
                }
                object obj;
                if (!values.TryGetValue(parameterName, out obj) || obj == null)
                {
                    return false;
                }
                if (obj is float)
                {
                    return true;
                }
                string s = Convert.ToString(obj, CultureInfo.InvariantCulture);
                float num;
                return float.TryParse(s, NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite | NumberStyles.AllowLeadingSign | NumberStyles.AllowDecimalPoint | NumberStyles.AllowThousands | NumberStyles.AllowExponent, CultureInfo.InvariantCulture, out num);
            }
        }
    View Code

    RouteCollection

    为 ASP.NET 路由操作提供路由的集合。

    public class RouteCollection : Collection<RouteBase>

    可以看出他是一个集合,我们用的类型一般为Route类,MVC注册路由里面使用的也是Route类型往集合中添加。

    在MVC中有为期扩展了一些方法  扩展类public static class RouteCollectionExtensions(扩展方法中  在注册路由的时候把Handler也注册进去了

    RouteTable

    存储应用程序的 URL 路由。

    //
    // 摘要:
    //     存储应用程序的 URL 路由。
    [TypeForwardedFrom("System.Web.Routing, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")]
    public class RouteTable
    {
        //
        // 摘要:
        //     初始化 System.Web.Routing.RouteTable 类的新实例。
        public RouteTable();
    
        //
            // 摘要:
            //     获取从 System.Web.Routing.RouteBase 类派生的对象的集合。
            //
            // 返回结果:
            //     包含集合中的所有路由的对象。
        public static RouteCollection Routes { get; }
    }
    View Code

    TouteTable 里面有一个静态变量  public static RouteCollection Routes { get; } 

    RouteData

    RouteData有别于以上几个类型,上面的类型都是在System.Web.dll程序集中的,而RouteData在System.Web.Mvc.dll中,是MVC中特有的,他在MVC的控制器中有一个变量。

    //
    // 摘要:
    //     获取在 ASP.NET 路由确定路由是否匹配请求时,传递到路由处理程序但未使用的自定义值的集合。
    //
    // 返回结果:
    //     一个包含自定义值的对象。
    public RouteValueDictionary DataTokens { get; }
    //
    // 摘要:
    //     获取或设置表示路由的对象。
    //
    // 返回结果:
    //     一个表示路由定义的对象。
    public RouteBase Route { get; set; }
    //
    // 摘要:
    //     获取或设置处理所请求路由的对象。
    //
    // 返回结果:
    //     一个处理路由请求的对象。
    public IRouteHandler RouteHandler { get; set; }
    //
    // 摘要:
    //     获取路由的 URL 参数值和默认值的集合。
    //
    // 返回结果:
    //     一个对象,其中包含根据 URL 和默认值分析得出的值。
    public RouteValueDictionary Values { get; }
    
    //
    // 摘要:
    //     使用指定标识符检索值。
    //
    // 参数:
    //   valueName:
    //     要检索的值的键。
    //
    // 返回结果:
    //     其键与 valueName 匹配的 System.Web.Routing.RouteData.Values 属性中的元素。
    //
    // 异常:
    //   T:System.InvalidOperationException:
    //     valueName 的值不存在。
    public string GetRequiredString(string valueName);
    View Code
    路由注册过程以及Handler

     1、管道模型中注册的module

    控制器中写一个action

    
    
    视图展示

    
    
    运行显示module,以及handler

    查看运行涉及到Module

    2、UrlRoutingModule

    定义:匹配定义的路由的 URL ,请求他是MVC框架的起点。       并且路由指定了MvcRouteHandler,最终的handler是MvcHandler。

    
    路由的方法调用流程

    
    上面用了很多虚方法,是为了扩展有用的。
    Module注册的事件是PostResolveRequestCache。所以Handler的分配是在这个里面的,和webform不一样
    
    源码中路由注册方法
    MvcHandler到控制器

     1、public class MvcHandler : IHttpAsyncHandler, IHttpHandler, IRequiresSessionState

    主要是在下图步骤3中得到控制器实例,然后控制器执行Execute方法

    2、public abstract class ControllerBase : IController

    在ControllerBase中执行Execute方法。但是在Execute中又执行了ExcuteCore这个抽象方法,这样又必须找他的子类中怎么实现的,通过下面Controller继承过程我们需要在找Controller类

    public abstract class Controller : ControllerBase, IActionFilter, IAuthenticationFilter, IAuthorizationFilter, IDisposable, IExceptionFilter, IResultFilter, IAsyncController, IController, IAsyncManagerContainer

    3、这个是Controller类中的ExecuteCore执行过程。

    当然这个执行过程一般的讲  是找到action名字,然后反射调用方法。复杂的讲还有请求协议(get post),方法重载等控制。

     

  • 相关阅读:
    vue vant 循环picker模块的实现方法
    Element的表单验证规则,清空或填充数据如何避免自动触发
    递归寻找树结构的子节点
    vue源码解析实例(二)---vue 虚拟DOM篇
    vue源码解析实例(一)
    变化侦测篇---Object.create(null)的定义
    vue源码-变化侦测篇(小知识点)
    Vue源码学习-开篇
    position: sticky轻松做出吸顶功能
    自适应图片高度蒙层 css
  • 原文地址:https://www.cnblogs.com/wudequn/p/7966846.html
Copyright © 2011-2022 走看看