目錄 1. ASP.NET 路由 註冊路由 動態映射HttpHandler 2. WebAPI 路由 註冊路由 調用GetRouteData 3. 2個路由系統銜接 GlobalConfiguration HostedHttpRoute 4. 補充 路由是進入Web API的第一扇門.目的用於確定C ...
目錄
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.cnblogs.com/p/5933752.html