版权声明:此文章转载自_infocool
原文链接:http://www.infocool.net/kb/ASP/201610/197689.html
如需转载请联系听云College团队成员小尹 邮箱:yinhy#tingyun.com
目录
ASP.NET 路由
注册路由
动态映射HttpHandler
WebAPI 路由
注册路由
调用GetRouteData
2个路由系统衔接
GlobalConfiguration
HostedHttpRoute
补充
路由是进入Web API的第一扇门.目的用于确定Controller名称、Action名称、路由参数.
ASP.NET 路由
注册路由
在ASP.NET中注册路由的方式:
RouteCollection.MapPageRoute()
添加1个完整的路由:
var defaults = new RouteValueDictionary//路由变量默认值 { {"code","010"}, {"phone","1000000"}, }; var constraints = new RouteValueDictionary//路由变量约束 { {"code",@"0\d{2,3}" }, {"phone",@"\d{7,9}" }, {"httpMethod",new HttpMethodConstraint("POST") } }; var dataTokens = new RouteValueDictionary//路由相关参数,不用于处理路由匹配功能 { {"defaultCode","北京" }, {"defaultPhone","北京X电话" } }; RouteTable.Routes.MapPageRoute("default", "{code}/{phone}", "~/call.aspx", false, defaults, constraints, dataTokens);
获取RouteCollection
一般通过RouteTable.Routes
public class RouteTable { private static RouteCollection _instance = new RouteCollection(); public static RouteCollection Routes { get { return RouteTable._instance; } } }
路由:RouteBase
public abstract class RouteBase { public bool RouteExistingFiles {get; set;} = true;//对现有文件进行路由 public abstract RouteData GetRouteData(HttpContextBase httpContext); public abstract VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values); }
路由默认实现:Route
public class Route : RouteBase { /// <summary> /// 路由约束 /// </summary> public RouteValueDictionary Constraints { get; set; } /// <summary> /// 路由自定义参数(一般存储备注说明等) /// </summary> public RouteValueDictionary DataTokens { get; set; } /// <summary> /// 路由变量默认值 /// </summary> public RouteValueDictionary Defaults { get; set; } /// <summary> /// 路由对应处理程序对象 /// </summary> public IRouteHandler RouteHandler { get; set; } /// <summary> /// 路由模板 /// </summary> public string Url { get; set; } }
忽略路由:
忽略路由本质是添加一个StopRoutingHandler(返回空的HttpHandler)的路由
routes.Ignore("010/1000001");(路由先注册,先匹配) routes.MapPageRoute("default", "{code}/{phone}", "~/call.aspx", false, defaults, constraints, dataTokens);
路由约束:
在上面完整的路由添加Demo中,路由约束有2种方式
正则表达式字符串
实现IRouteConstraint接口
动态映射HttpHandler
路由是通过UrlRoutingModule这个HttpModule实现动态拦截.
public virtual void PostResolveRequestCache(HttpContextBase context) { RouteData routeData = RouteTable.Routes.GetRouteData(context); IRouteHandler routeHandler = routeData.RouteHandler; IHttpHandler httpHandler = routeHandler.GetHttpHandler(new RequestContext(context, routeData)); context.RemapHandler(httpHandler); }
WebAPI 路由
注册路由
在Web API中注册路由的方式:HttpRouteCollection.MapHttpRoute(),
这里重点看下MapHttpRoute方法内部
public static class HttpRouteCollectionExtensions { public static IHttpRoute MapHttpRoute(this HttpRouteCollection routes, string name, string routeTemplate, object defaults, object constraints, HttpMessageHandler handler) { IHttpRoute route = routes.CreateRoute(routeTemplate, (IDictionary<string, object>)defaults, (IDictionary<string, object>)constraints, (IDictionary<string, object>)null, handler); routes.Add(name, route); return route; } }
获取HttpRouteCollection
在WebAPI中通过HttpConfiguration的Routes属性
public class HttpConfiguration : IDisposable { public Collection<DelegatingHandler> MessageHandlers { get; } public HttpRouteCollection Routes { get; } public ConcurrentDictionary<object, object> Properties { get; } }
WebAPI路由:IHttpRoute
public interface IHttpRoute { string RouteTemplate { get; } IDictionary<string, object> Defaults { get; } IDictionary<string, object> Constraints { get; } IDictionary<string, object> DataTokens { get; } HttpMessageHandler Handler { get; } IHttpRouteData GetRouteData(string virtualPathRoot, HttpRequestMessage request); IHttpVirtualPathData GetVirtualPath(HttpRequestMessage request, IDictionary<string, object> values); }
WebAPI路由默认实现:HttpRoute
由于IHttpRoute设计的非常全,HttpRoute基本就是实现了IHttpRoute.
(这种设计上比RouteBase要优势很多)
调用GetRouteData
与ASP.NET稍微不同的是
直接对所有请求进行路由 而不再判断是否文件存在.
添加一个VirtualPathRoot的过滤
public class HttpRouteCollection { public virtual IHttpRouteData GetRouteData(HttpRequestMessage request) { string virtualPathRoot = request.GetRequestContext().VirtualPathRoot; IHttpRouteData routeData = this._collection[index].GetRouteData(virtualPathRoot, request); return routeData; } }
2个路由系统衔接
Web API提供了一套自身的路由系统,所以不依赖于ASP.NET.
寄宿方式有多种.如果以WebHost的方式.本质上还是走的ASP.NET路由处理.
GlobalConfiguration
WebAPI的配置在HttpConfiguration中提供.
在WebHost中,定义了GlobalConfiguration用来创建HttpConfiguration
public static class GlobalConfiguration
{
public static HttpConfiguration Configuration = GlobalConfiguration.CreateConfiguration();//创建HttpConfiguration
public static HttpMessageHandler DefaultHandler = GlobalConfiguration.CreateDefaultHandler();//创建HttpRoutingDispatcher(WebAPI管道尾部HttpMessageHandler) public static HttpServer DefaultServer = GlobalConfiguration.CreateDefaultServer();//创建HttpServer(WebAPI管道开头HttpMessageHandler) public static void Configure(Action<HttpConfiguration> configurationCallback)//提供方便配置路由 { configurationCallback(GlobalConfiguration.Configuration); } private static Lazy<HttpConfiguration> CreateConfiguration() { return new Lazy<HttpConfiguration>((Func<HttpConfiguration>) (() => { //这里用HostedHttpRouteCollection实现HttpRouteCollection return new HttpConfiguration((HttpRouteCollection) new HostedHttpRouteCollection(RouteTable.Routes)); })); } }
HostedHttpRoute
在GlobalConfiguration中创建的HttpConfiguration对象是用HostedHttpRouteCollection作为参数
这里我觉得有必要看下CreateRoute和Add方法
internal class HostedHttpRouteCollection : HttpRouteCollection { //真正维护的路由集合 private readonly RouteCollection _routeCollection; //创建路由 MapHttpRoute会调用该方法 public override IHttpRoute CreateRoute(string uriTemplate, IDictionary<string, object> defaults, IDictionary<string, object> constraints, IDictionary<string, object> dataTokens, HttpMessageHandler handler) { return (IHttpRoute) new HostedHttpRoute(uriTemplate, defaults, constraints, dataTokens, handler); } public override void Add(string name, IHttpRoute route) { //只是添加到内部的routeCollection中 //route.ToRoute() => route.OriginalRoute; this._routeCollection.Add(name, (RouteBase) route.ToRoute()); } public override IHttpRouteData GetRouteData(HttpRequestMessage request) { //通过调用内部的Route的GetRouteData RouteData routeData = this._routeCollection.GetRouteData(httpContextBase); return (IHttpRouteData)new HostedHttpRouteData(routeData); } }
而HostedHttpRoute在WebHost中
相当于用HttpRoute的身 却提供了真正的Route
internal class HostedHttpRoute : IHttpRoute { //ASP.NET Route internal Route OriginalRoute { get; private set; } public HostedHttpRoute(string uriTemplate, IDictionary<string, object> defaults, IDictionary<string, object> constraints, IDictionary<string, object> dataTokens, HttpMessageHandler handler) { //内部的OriginalRoute实际为HttpWebRoute this.OriginalRoute = (Route) new HttpWebRoute(uriTemplate, defaults1, constraints1, dataTokens1, <strong>(IRouteHandler) HttpControllerRouteHandler.Instance</strong>, (IHttpRoute) this); this.Handler = handler; } }
从HostedHttpRoute构造函数中 我们看到了真正的Route为HttpWebRoute 且RouteHandler为HttpControllerRouteHandler.Instance
public class HttpControllerRouteHandler : IRouteHandler { public static HttpControllerRouteHandler Instance{ get { return new HttpControllerRouteHandler(); } } protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext) { return (IHttpHandler) new HttpControllerHandler(requestContext.RouteData); } }
补充
冗余的设计:
HttpRoute中Handler的HttpMessageHandler,未发现有任何地方使用到.
HttpRoute和Route中DataTokens,建议直接取消.
备注:
文章中的代码并非完整,一般是经过自己精简后的.
本篇内容使用MarkDown语法编辑
首发地址:http://neverc.infocool.net/p/5933752.html