ASP.NET MVC路由系统的核心对象介绍

众所周知,ASP.NET MVC有一套自己的路由系统。这套路由系统是在原来的ASP.NET 路由系统上扩展过来的。今天这篇文章就来聊聊MVC路由系统中非常关键的一些对象。

ASP.NET MVC路由系统主要由以下几个核心对象:

        1.RouteCollection(RouteCollextionExtentions)

        2.RouteTable

        3.RouteData

        4.Route:RouteBase

        5.URLRouteMoudle

        下面我们就来一一介绍这些对象

RouteCollection:这个是提供ASP.NET路由的路由集合,而MVC的路由类RouteCollectionExtentions中的方法是从RouteCollection扩展过来的扩展方法,它负责MVC的路由工作。下面是这个类的代码。

    public static class RouteCollectionExtensions
    {

        public static VirtualPathData GetVirtualPathForArea(this RouteCollection routes, RequestContext requestContext, RouteValueDictionary values);
        public static VirtualPathData GetVirtualPathForArea(this RouteCollection routes, RequestContext requestContext, string name, RouteValueDictionary values);
        public static void IgnoreRoute(this RouteCollection routes, string url);
        public static void IgnoreRoute(this RouteCollection routes, string url, object constraints);
        public static Route MapRoute(this RouteCollection routes, string name, string url);
        public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults);
        public static Route MapRoute(this RouteCollection routes, string name, string url, string[] namespaces);
        public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, object constraints);
        public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, string[] namespaces);
        public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces);
    }

从上面的定义可以看得出来,RouteCollectionExtentions类中的成员都是扩展成员。MapRoute方法是核心,该方法向路由表中注册路由。IgnoreRoute向路由表中注册忽略路由。

RouteTable:路由表。顾名思义,这个类存储了我们注册的路由。而且这个对象在整个网站中只能有一个。接下来我们看一下这个类的代码(这是我用反编译工具编译出来的代码)。

public class RouteTable
{
    // Fields
    private static RouteCollection _instance;

    // Methods
    static RouteTable();
    [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
    public RouteTable();

    // Properties
    public static RouteCollection Routes { [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] get; }
}

可以看得出来,RouteTable维护了一个RouteCollection类型的静态字段。这个字段中存储了我们网站的所有路由。然后它有一个静态构造函数和一个实例构造函数。最后是一个返回值为RouteCollection的Routes属性,它实际上是对_instance字段的封装。

RouteData:路由数据。这个对象存储的是我们的路由数据。客户端请求过来的相关参数会存储在这个类里面,比如客户端请求的控制器名称,Action名称,QueryString等都可以存储在这个对象里面。

public class RouteData
{
    // Fields
    private RouteValueDictionary _dataTokens;
    private IRouteHandler _routeHandler;
    private RouteValueDictionary _values;

    // Methods
    public RouteData();
    public RouteData(RouteBase route, IRouteHandler routeHandler);
    public string GetRequiredString(string valueName);

    // Properties
    public RouteValueDictionary DataTokens { [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] get; }
    public RouteBase Route { [CompilerGenerated, TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] get; [CompilerGenerated, TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] set; }
    public IRouteHandler RouteHandler { [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] get; [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] set; }
    public RouteValueDictionary Values { [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] get; }
}

在这个类中,有两个非常关键的字段_dataTokens和_values,它们都是RouteValueDictionary类型的字段,因为RouteValueDictionary实现了集合类接口,所以本质上他还是一个键值对类型的类。实际上,客户端请求的控制器名,Action名,参数都会存储在_values字段中,而命名空间则会存储在_dataTokens中。

_routeHandler在MVC中具体指的是MVCRouteHandler,它是用来创建MVCHandler的对象,而MVCHandler是真正用来处理一次mvc请求的处理程序。Route属性表示生成该RouteData对象的路由对象。其他的几个属性实际上是对前面字段的封装。

RouteBase:它是所有Route对象的基类,代码如下:

public abstract class RouteBase
{
    // Fields
    private bool _routeExistingFiles;

    // Methods
    protected RouteBase();
    public abstract RouteData GetRouteData(HttpContextBase httpContext);
    public abstract VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values);

    // Properties
    public bool RouteExistingFiles { [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] get; [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] set; }
}

它声明了两个非常关键的抽象方法:GetRouteData和GetVirtualPath。每个Route类都必须实现它。前者用来获取路由数据,后者用来获取虚拟路径。

Route:它是真正用来匹配路由的类代码如下:

public class Route : RouteBase
{
    // Fields
    private ParsedRoute _parsedRoute;
    private string _url;
    private const string HttpMethodParameterName = "httpMethod";

    // Methods
    public Route(string url, IRouteHandler routeHandler);
    public Route(string url, RouteValueDictionary defaults, IRouteHandler routeHandler);
    public Route(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, IRouteHandler routeHandler);
    public Route(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, RouteValueDictionary dataTokens, IRouteHandler routeHandler);
    public override RouteData GetRouteData(HttpContextBase httpContext);
    public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values);
    protected virtual bool ProcessConstraint(HttpContextBase httpContext, object constraint, string parameterName, RouteValueDictionary values, RouteDirection routeDirection);
    private bool ProcessConstraints(HttpContextBase httpContext, RouteValueDictionary values, RouteDirection routeDirection);

    // Properties
    public RouteValueDictionary Constraints { [CompilerGenerated, TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] get; [CompilerGenerated, TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] set; }
    public RouteValueDictionary DataTokens { [CompilerGenerated, TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] get; [CompilerGenerated, TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] set; }
    public RouteValueDictionary Defaults { [CompilerGenerated, TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] get; [CompilerGenerated, TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] set; }
    public IRouteHandler RouteHandler { [CompilerGenerated, TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] get; [CompilerGenerated, TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] set; }
    public string Url { get; set; }
}

其中url字段用来存储路由模板,如"{controller}/{action}/{id}"就是一个路由模板。GetRouteData是核心,它根据当前请求上下文来判断客户端的本次请求是否和本路由规则匹配,如果匹配则返回一个RoutaData对象,RouteData的IRoute会被赋值,这个值会体现在RouteData的同名属性上。而它的RouteHandler属性会在MapRoute也就是注册路由的时候被赋值,这个值就是MVCRouteHandler,然后这个值体现到RouteData的同名属性上。

那么MVC是如何进行路由匹配呢,这里就不得不说UrlRoutingMoudle对象,它实现了IHttpMoudle对象,向ASP.NET 事件管道里面注册事件,代码如下:

public class UrlRoutingModule : IHttpModule
{
    // Fields
    private static readonly object _contextKey;
    private static readonly object _requestDataKey;
    private RouteCollection _routeCollection;

    // Methods
    static UrlRoutingModule();
    [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
    public UrlRoutingModule();
    protected virtual void Dispose();
    protected virtual void Init(HttpApplication application);
    private void OnApplicationPostResolveRequestCache(object sender, EventArgs e);
    [Obsolete("This method is obsolete. Override the Init method to use the PostMapRequestHandler event.")]
    public virtual void PostMapRequestHandler(HttpContextBase context);
    public virtual void PostResolveRequestCache(HttpContextBase context);
    [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
    void IHttpModule.Dispose();
    [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
    void IHttpModule.Init(HttpApplication application);

    // Properties
    public RouteCollection RouteCollection { get; [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] set; }
}

这个Moudle向事件管道注册的时间为PostResolveRequestCache。它的代码如下,相信大家看了以后会知道是怎么回事。

public virtual void PostResolveRequestCache(HttpContextBase context)
{
    RouteData routeData = this.RouteCollection.GetRouteData(context);
    if (routeData != null)
    {
        IRouteHandler routeHandler = routeData.RouteHandler;
        if (routeHandler == null)
        {
            throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, SR.GetString("UrlRoutingModule_NoRouteHandler"), new object[0]));
        }
        if (!(routeHandler is StopRoutingHandler))
        {
            RequestContext requestContext = new RequestContext(context, routeData);
            context.Request.RequestContext = requestContext;
            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
            {
                context.RemapHandler(httpHandler);
            }
        }
    }
}
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对象,所以网站启动的时候,最先注册的路由是最先被拿去做匹配的。

时间: 2024-10-10 01:04:28

ASP.NET MVC路由系统的核心对象介绍的相关文章

ASP.NET MVC - 路由系统

ASP.NET MVC的请求URL不再对应于传统ASP.NET程序的ASPX文件物理地址,而是把请求映射到一个控制器(Controller)类的方法(Action)上,Controller.Action再加上参数构成ASP.Net MVC请求的Url.下面我们来看下路由系统的主要对象. UrlRoutingModule ASP.NET MVC框架的路由实质是从传统ASP.NET管道扩展HttpModule而来,这个模块正是UrlRoutingModule.通过反编译可以看到UrlRoutingM

ASP.NET Core的路由[2]:路由系统的核心对象——Router

ASP.NET Core应用中的路由机制实现在RouterMiddleware中间件中,它的目的在于通过路由解析为请求找到一个匹配的处理器,同时将请求携带的数据以路由参数的形式解析出来供后续请求处理流程使用.但是具体的路由解析功能其实并没有直接实现在RouterMiddleware中间件中,而是由一个Router对象来完成的.[本文已经同步到<ASP.NET Core框架揭秘>之中] 目录一.IRouter接口二.RouteContext三.RouteData四.Route五.RouteHan

探索ASP.NET MVC路由系统

引言 对于ASP.NET MVC的路由系统相信大家肯定不陌生.今天我们就深入ASP.NET的框架内部来看一下路由系统到底是怎么通过我们给出的地址(例如:/Home/Index)解析出Controller和Action.今天的这一篇文章我们就深入框架内部,看看里面的流程. UrlRouteModule介绍 ASP.NET MVC本质上是通过IHttpModule和IHttpHandler两个组件对ASP.NET框架进行扩展来实现的.ASP.NET 请求处理过程是基于管道模型的,这个管道模型是由多个

ASP.NET MVC 路由系统类

RouteData public class RouteData { private RouteValueDictionary _dataTokens; private IRouteHandler _routeHandler; private RouteValueDictionary _values; public RouteData() { this._values = new RouteValueDictionary(); this._dataTokens = new RouteValueD

[Buffalo]ASP.NET MVC路由映射

Asp.Net的路由系统旨在通过注册URl模版与物理文件之间的映射进而实现请求地址与文件路径之间的分离,但对于Asp.Net Mvc应用来说,请求的目标却是定义在某个Controller类型中的Action方法. 为了实现针对目标Controller和Action的路由,Asp.Net Mvc在System.Web.Mvc.RouteCollectionExtensions中针对RouteConllection类型定义了一系列的扩展方法以实现文件路径无关的路由映射.其中的两组方法,Ignore用

ASP.NET的路由系统:路由映射

总的来说,我们可以通过RouteTable的静态属性Routes得到一个基于应用的全局路由表,通过上面的介绍我们知道这是一个类型的RouteCollection的集合对象,我们可以通过调用它的MapPageRoute进行路由映射,即注册URL模板与某个物理文件的匹配关系.路由注册的核心就是在全局路由表中添加一个Route对象,该对象的绝大部分属性都可以通过MapPageRoute方法的相关参数来指定.接下来我们通过实现演示的方式来说明路由注册的一些细节问题. 目录 一.变量默认值 二.约束 三.

ASP.NET MVC路由(二)

 ASP.NET MVC路由(二) 前言 在上一篇中,提及了Route.RouteCollection对象的一些信息,以及它们的结构所对应的关系.按照处理流程走下来还有遗留的疑问没有解决这个篇幅就来讲解一下. URL规则的生成 Url规则看名字挺吓唬人的,其实就是根据我们自定义的Url来解析出一个模式,然后等待请求的Url来的时候,跟我们定义的模式进行匹配(如下图).这是后续的内容. 在上篇中说到URL规则的定义是在Route对象中的,下面来讲解在Route对象中怎么根据用户注册的URL转变成U

ASP.NET MVC 路由(四)

ASP.NET MVC 路由(四) 前言 在前面的篇幅中我们讲解路由系统在MVC中的运行过程以及粗略的原理,想必看过前面篇幅的朋友应该对路由有个概念性的了解了,本篇来讲解区域,在读完本篇后不会肯定的让你对区域有彻底的了解,但是会让你在以后对这部分知识掌握的路上夯上厚实的基础. 区域 在路由的起初在按照VS环境新建的MVC项目来讲的,今天区域也是按照这样的套路来讲.MSDN上说,在大型项目使用中被MVC划分为较小单元也就是区域,我没有使用过区域的经验,所以这篇只能讲解它的对象模型以及粗略的原理.

ASP.NET MVC路由(四)

ASP.NET MVC路由(四) 前言 在前面的篇幅中我们讲解路由系统在MVC中的运行过程以及粗略的原理,想必看过前面篇幅的朋友应该对路由有个概念性的了解了,本篇来讲解区域,在读完本篇后不会肯定的让你对区域有彻底的了解,但是会让你在以后对这部分知识掌握的路上夯上厚实的基础. 区域 在路由的起初在按照VS环境新建的MVC项目来讲的,今天区域也是按照这样的套路来讲.MSDN上说,在大型项目使用中被MVC划分为较小单元也就是区域,我没有使用过区域的经验,所以这篇只能讲解它的对象模型以及粗略的原理. (