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:
可以自定义做一些限制等操作,比如限制域名
////// 支持泛域名的UrlRouting /// 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 _pathSegmentLists = new List (); 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 构造函数 /// /// /// /// 泛域名 /// Url路由 /// 映射的物理文件 /// 一个值,该值指示 ASP.NET 是否应验证用户是否有权访问物理 URL(始终会检查路由 URL)。此参数设置 System.Web.Routing.PageRouteHandler.CheckPhysicalUrlAccess /// 路由的默认值。 /// 一些约束,URL 请求必须满足这些约束才能作为此路由处理。 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 属性 /// /// 泛域名 /// public string DomainName { get { return this._domainName; } set { this._domainName = value; } } /// /// 映射的物理文件 /// public string PhysicalFile { get { return this._physicalFile; } set { this._physicalFile = value; } } /// /// Url路由 /// 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));