由于之前分析过详细的源码单步解析,所以这里不再每一步探究具体的细节,而是上升一个层面以总结和回顾的形式来看待
在webapi中是采用先将路由和处理程序注册,在处理请求时根据路由信息找到处理程序,注册流程如下
一个web应用有一个全局的路由表,并通过RouteTable.Route来表示,它的返回值类型是一个继承自Collection直接
或者间接
的添加到路由表中。
web Form中添加路由是最直观的阐述了上面的介绍,因为在webform中我们直接
使用RouteCollection类型的实例方法MapPageRoute就可以了,而在web API应用中是有点不一样的。
var Routes = RouteTable.Routes; Routes.MapPageRoute("", "Test/{name}/{id}","~/default.aspx", true, defaults);
WEB Api注册路由入口
public static void Register(HttpConfiguration config) { config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); } protected void Application_Start() { GlobalConfiguration.Configure(WebApiConfig.Register); }
这里的config.Routes就是一个HttpRouteCollection对象
在webapi中绑定路由,其实最终也是绑定到全局路由表RouteTable上,但是过程却稍微间接
一些,是通过一个类型为HttpRouteCollection或者继承自它的实例扩展方法来进行绑定的.
1.首先在webapi应用初始化时默认创建了继承自HttpRouteCollection类型的HostedHttpRouteCollection的实例并将全局路由表RouteTable.Routes传入
2.返回一个HttpConfiguration的实例config作为WebApiConfig.Register的参数,然后调用扩展方法来添加路由到RouteTable上,当然其中有一些细节是不一样的,目前先省略
3.顺便说一下包括路由注册在内对整个Web API管道的配置都是通过HttpConfiguration来完成的,一切可以从GlobalConfiguration静态类中找到答案
由于web API框架是一个抽象的消息处理管道,具有自己的路由系统,并且它是由一系列注册实现了IHttpRoute接口的HttpRoute对象组成
1.在GlobalConfiguration中的CreateConfiguration方法返回的我们可以看到HttpConfiguration包含的类型是一个HostedHttpRouteCollection类型.
private static Lazy<HttpConfiguration> CreateConfiguration() { return new Lazy<HttpConfiguration>(() => { HttpConfiguration config = null; var newInstance = new HostedHttpRouteCollection(RouteTable.Routes); config = new HttpConfiguration(newInstance); return config; }); }
2.包含在HostedHttpRouteCollection之中的创建出的Route类型是一个HostedHttpRoute
public override IHttpRoute CreateRoute(string uriTemplate, IDictionary<string, object> defaults, IDictionary<string, object> constraints, IDictionary<string, object> dataTokens, HttpMessageHandler handler) { return new HostedHttpRoute(uriTemplate, defaults, constraints, dataTokens, handler); }
3.在HostedHttpRouteCollection中有一个RouteCollection类型的字段_routeCollection 并且在初始化时将RouteTable.Routes传递给了它
public HostedHttpRouteCollection(RouteCollection routeCollection) : this(routeCollection, virtualPathRoot: null) { } public HostedHttpRouteCollection(RouteCollection routeCollection, string virtualPathRoot) { _routeCollection = routeCollection; _virtualPathRoot = virtualPathRoot; }
4.在类中重写了Add方法,它会将指定的HttpRoute对象转为Route,并且添加到ASP.NET的全局路由表中,到这里说明在webapi webHost中依然还是采用的ASP.NET路由,只不过在实现上做了一些调整
public override void Add(string name, IHttpRoute route) { _routeCollection.Add(name, route.ToRoute()); }
1.通过原来的学习我们知道,在ASP .NET中整个路由的核心是UrlRoutingModule的HttpModule,在UrlRoutingModule中根据请求上下文得到当前路由的路由处理程序IRouteHandler
UrlRoutingModule处理代码
public virtual void PostResolveRequestCache(HttpContextBase context) { //根据请求获取注册的路由信息 RouteData routeData = RouteCollection.GetRouteData(context); //获取到路由信息的路由处理程序 IRouteHandler routeHandler = routeData.RouteHandler; RequestContext requestContext = new RequestContext(context, routeData); context.Request.RequestContext = requestContext; //由路由处理程序得到具体处理的HttpHanlder IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext); }
2.此时得到的是一个HttpControllerRouteHandler对象的路由处理程序,然后在根据路由处理程序获取到HttpControllerHandler,最终处理由HttpControllerHandler中的ProcessRequestAsyncCore方法处理,也同时标志此时请求将正式被WEB Api管道接管开始执行
internal async Task ProcessRequestAsyncCore(HttpContextBase contextBase) { HttpRequestMessage request = contextBase.GetHttpRequestMessage() ?? ConvertRequest(contextBase); HttpResponseMessage response = null; try { //开始进入管道 response = await _server.SendAsync(request, cancellationToken); } catch (OperationCanceledException) { } finally { } }