.NET UrlRouting原理

UrlRouting路由流程:

添加路由:可以通过调用MapRoute()、MapPageRoute(),它们内部都是创建Route对象,最终添加到RouteCollection中。

    还可以使用[Route("/home/index")]的方式添加,注册路由时需要执行RouteConfig.RegisterRoutes(RouteTable.Routes);

    或者直接调用RouteCollection.Add()方法注册路由

匹配路由:调用RouteCollection的GetRouteData(),最终调用Route中的GetRouteData(),如果返回非null,则匹配

排除路由:IgnoreRoute(),也是往RouteCollection中添加了一个Route对象,Route中的handler是StopRoutingHandler。在路由配置时,如果匹配到的路由的Handler是StopRoutingHandler,请求中断

说明:

MapRoute()是添加MVC路由,MapPageRoute()是添加WebForm路由。它们的RouteHandler不同,MVC的是MVCRouteHandler,WebForm的是PageRouteHandler

MVCRouteHandler内部可以获取到IHttpHandler,实现类是MVCHander,它的PR方法中创建Controller,并调用Action

PageRouteHandler同上,它的IHttpHandler的实现类是Page,Page中有几个事件,我们可以在事件回调中做操作。

MVC和WebForm都是用的ASP.NET框架,从路由开始有了差别,一个创建Controller,一个创建Page。

自定义Route:

可以自定义做一些限制等操作,比如限制域名

    /// <summary>
    /// 支持泛域名的UrlRouting
    /// </summary>
    public class DomainRoute : RouteBase
    {
        #region 变量
        private string _domainName;
        private string _physicalFile;
        private string _routeUrl;
        private bool _checkPhysicalUrlAccess = false;
        private RouteValueDictionary _defaults;
        private RouteValueDictionary _constraints;
        private IList<PathSegment> _pathSegmentLists = new List<PathSegment>();
        private const string REPLACE_PATTEN = @"([w,%]+)";
        private readonly Regex _patten = new Regex(@"{([a-z,A-Z,0-9]+)}", RegexOptions.Compiled);
        private int _segmentCount = 0;
        #endregion

        #region 构造函数
        /// <summary>
        /// 
        /// </summary>
        /// <param name="domainName">泛域名</param>
        /// <param name="routeUrl">Url路由</param>
        /// <param name="physicalFile">映射的物理文件</param>
        /// <param name="checkPhysicalUrlAccess">一个值,该值指示 ASP.NET 是否应验证用户是否有权访问物理 URL(始终会检查路由 URL)。此参数设置 System.Web.Routing.PageRouteHandler.CheckPhysicalUrlAccess</param>
        /// <param name="defaults">路由的默认值。</param>
        /// <param name="constraints">一些约束,URL 请求必须满足这些约束才能作为此路由处理。</param>

        public DomainRoute(string domainName, string routeUrl, string physicalFile, bool checkPhysicalUrlAccess, RouteValueDictionary defaults, RouteValueDictionary constraints)
        {
            this._domainName = domainName.ToLower();
            this._routeUrl = routeUrl;
            this._physicalFile = physicalFile;
            this._checkPhysicalUrlAccess = checkPhysicalUrlAccess;
            this._defaults = defaults;
            this._constraints = constraints;

            IList<string> lists = SplitUrlToPathSegmentStrings(routeUrl);
            if (lists != null && lists.Count > 0)
            {
                this._segmentCount = lists.Count;
                for (int i = 0; i < lists.Count; i++)
                {
                    string strPatten = lists[i];
                    if (!string.IsNullOrWhiteSpace(strPatten) && this._patten.IsMatch(strPatten))
                    {
                        PathSegment segment = new PathSegment();
                        segment.Index = i;

                        Match match;
                        List<string> valueNames = new List<string>();
                        for (match = this._patten.Match(strPatten); match.Success; match = match.NextMatch())
                        {
                            strPatten = strPatten.Replace(match.Groups[0].Value, REPLACE_PATTEN);
                            valueNames.Add(match.Groups[1].Value);
                        }
                        segment.ValueNames = valueNames.ToArray();
                        segment.Regex = new Regex(strPatten, RegexOptions.Compiled | RegexOptions.IgnoreCase);
                        this._pathSegmentLists.Add(segment);
                    }
                }
            }
        }

        public DomainRoute(string domainName, string routeUrl, string physicalFile)
            : this(domainName, routeUrl, physicalFile, false, new RouteValueDictionary(), new RouteValueDictionary())
        {

        }
        #endregion

        #region 属性
        /// <summary>
        /// 泛域名
        /// </summary>
        public string DomainName
        {
            get { return this._domainName; }
            set { this._domainName = value; }
        }
        /// <summary>
        /// 映射的物理文件
        /// </summary>
        public string PhysicalFile
        {
            get { return this._physicalFile; }
            set { this._physicalFile = value; }
        }
        /// <summary>
        /// Url路由
        /// </summary>
        public string RouteUrl
        {
            get { return this._routeUrl; }
            set { this._routeUrl = value; }
        }
        #endregion

        #region 方法
        [DebuggerStepThrough]
        public override RouteData GetRouteData(HttpContextBase httpContext)
        {
            RouteData result = null;
            HttpRequestBase request = httpContext.Request;
            if (request.Url.Host.ToLower().Contains(this._domainName))
            {
                string virtualPath = request.AppRelativeCurrentExecutionFilePath.Substring(2) + request.PathInfo;
                IList<string> segmentUrl = SplitUrlToPathSegmentStrings(virtualPath);
                if (segmentUrl.Count == this._segmentCount)
                {
                    PathSegment pathSegment = null;
                    string path = null;
                    bool isOK = true;
                    for (int i = 0; i < this._pathSegmentLists.Count; i++)
                    {
                        pathSegment = this._pathSegmentLists[i];
                        path = segmentUrl[pathSegment.Index];
                        if (!pathSegment.Regex.IsMatch(path))
                        {
                            isOK = false;
                            break;
                        }
                    }
                    if (isOK)
                    {
                        result = new RouteData(this, new PageRouteHandler(this._physicalFile, this._checkPhysicalUrlAccess));
                        result.Values.Add("Domain", this._domainName);
                        Match match = null;
                        for (int i = 0; i < this._pathSegmentLists.Count; i++)
                        {
                            pathSegment = this._pathSegmentLists[i];
                            path = segmentUrl[pathSegment.Index];
                            match = pathSegment.Regex.Match(path);
                            if (pathSegment.ValueNames.Length + 1 == match.Groups.Count)
                            {
                                for (int j = 0; j < pathSegment.ValueNames.Length; j++)
                                {
                                    result.Values.Add(pathSegment.ValueNames[j], match.Groups[j + 1].Value);
                                }
                            }
                        }
                    }
                }
                segmentUrl.Clear();
                segmentUrl = null;
            }
            return result;
        }

        public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
        {
            return new VirtualPathData(this, this._physicalFile);
        }

        private static IList<string> SplitUrlToPathSegmentStrings(string url)
        {
            List<string> list = new List<string>();
            if (!string.IsNullOrEmpty(url))
            {
                int index;
                for (int i = 0; i < url.Length; i = index + 1)
                {
                    index = url.IndexOf('/', i);
                    if (index == -1)
                    {
                        string str = url.Substring(i);
                        if (str.Length > 0)
                        {
                            list.Add(str);
                        }
                        return list;
                    }
                    string item = url.Substring(i, index - i);
                    if (item.Length > 0)
                    {
                        list.Add(item);
                    }
                    //list.Add("/");
                }
            }
            list.TrimExcess();
            return list;
        }
        #endregion

        #region 内部类
        private class PathSegment
        {
            public int Index { get; set; }
            public Regex Regex { get; set; }
            public string[] ValueNames { get; set; }
        }
        #endregion
    }

添加路由:

 RouteTable.Routes.Add(new DomainRoute(urlRoutingSetting.DomainName, urlRoutingSetting.RouteUrl, urlRoutingSetting.PhysicalFile, urlRoutingSetting.CheckPhysicalUrlAccess, urlRoutingSetting.Defaults, constraints)); 

原文地址:https://www.cnblogs.com/fanfan-90/p/12078975.html