routeBuilder.Build() 构建了一个集合 RouteCollection,用来保存所有的 IRouter 处理程序信息,包括用户配置的Router。
RouteCollection 本身也实现了 IRouter , 所以它也具有路由处理的能力。
Routing 中间件的入口是 RouterMiddleware 这个类,通过这个中间件注册到 Http 的管道处理流程中, ASP.NET Core MVC 会把它默认的作为其配置项的一部分,当然你也可以把Routing单独拿出来使用。
我们来看一下 Invoke 方法里面做了什么,它位于RouterMiddleware.cs 文件中。
public async Task Invoke(HttpContext httpContext)
{
var context = new RouteContext(httpContext);
context.RouteData.Routers.Add(_router);
await _router.RouteAsync(context);
if (context.Handler == null)
{
_logger.RequestDidNotMatchRoutes();
await _next.Invoke(httpContext);
}
else
{
httpContext.Features[typeof(IRoutingFeature)] = new RoutingFeature()
{
RouteData = context.RouteData,
};
await context.Handler(context.HttpContext);
}
}
首先,通过 httpContext 来初始化路由上下文(RouteContext),然后把用户配置的路由规则添加到路由上下文RouteData中的Routers中去。
接下来 await _router.RouteAsync(context) , 就是用到了 IRouter 接口中的 RouteAsync 方法了。
我们接着跟踪 RouteAsync 这个函数,看其内部都做了什么? 我们又跟踪到了RouteCollection.cs 这个类:
我们看一下 RouteAsync 的流程:
public async virtual Task RouteAsync(RouteContext context)
{
var snapshot = context.RouteData.PushState(null, values: null, dataTokens: null);
for (var i = 0; i < Count; i++)
{
var route = this[i];
context.RouteData.Routers.Add(route);
try
{
await route.RouteAsync(context);
if (context.Handler != null)
{
break;
}
}
finally
{
if (context.Handler == null)
{
snapshot.Restore();
}
}
}
}
我觉得这个类,包括函数设计的很巧妙,如果是我的话,我不一定能够想的出来,所以我们通过看源码也能够学到很多新知识。
为什么说设计的巧妙呢? RouteCollection 继承了 IRouter 但是并没有具体的对路由进行处理,而是通过循环来重新将路由上下文分发的具体的路由处理程序上。我们来看一下他的流程:
1、为了提高性能,创建了一个RouteDataSnapshot 快照对象,RouteDataSnapshot是一个结构体,它存储了 Route 中的路由数据信息。
2、循环当前 RouteCollection 中的 Router,添加到 RouterContext里的Routers中,然后把RouterContext交给Router来处理。
3、当没有处理程序处理当前路由








