1.路由基本介绍
由于之前分析过详细的源码单步解析,所以这里不再每一步探究具体的细节,而是上升一个层面以总结和回顾的形式来看待在webapi中是采用先将路由和处理程序注册,在处理请求时根据路由信息找到处理程序,注册流程如下
一个web应用有一个全局的路由表,并通过RouteTable.Route来表示,它的返回值类型是一个继承自Collection直接或者间接的添加到路由表中。
1.Web Form中的路由绑定
web Form中添加路由是最直观的阐述了上面的介绍,因为在webform中我们直接使用RouteCollection类型的实例方法MapPageRoute就可以了,而在web API应用中是有点不一样的。
var Routes = RouteTable.Routes;
Routes.MapPageRoute("", "Test/{name}/{id}","~/default.aspx", true, defaults);
2.Web API中的路由绑定
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静态类中找到答案
3.HostedHttpRouteCollection
由于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());
}
4.HttpControllerRouteHanlder和HttpControllerHanlder
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
{
}
}