路由中间件
- 首先看路由中间件的源码
- 先用
httpContext
实例化一个路由上下文,然后把中间件接收到的路由添加到路由上下文的路由集合 - 然后把路由上下文作为参数,调用
IRouter.RouteAsync
方法,该方法主要是进行路由匹配,匹配成功后给context.Handler
赋值 - 如果路由匹配成功,且handler不为空,说明已经有了后续处理消息的通道,就不用走下一个中间件了,否则消息处理交给下一个中间件
- MVC流程就是从这里开始,路由匹配成功后,从handler进入MVC流程
namespace Microsoft.AspNetCore.Builder
{
public class RouterMiddleware
{
private readonly ILogger _logger;
private readonly RequestDelegate _next;
private readonly IRouter _router;
public RouterMiddleware(
RequestDelegate next,
ILoggerFactory loggerFactory,
IRouter router)
{
_next = next;
_router = router;
_logger = loggerFactory.CreateLogger<RouterMiddleware>();
}
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);
}
}
}
}
路由
IRouter
接口仅定义了两个方法,其中路由的核心在于RouteAsync
方法,该方法可用于路由匹配,返回处理委托RouteBase
抽象类的的RouteAsync
方法进行路由的匹配,Route
类的RouteAsync
方法仅仅是执行了构造函数传进来的routeBuilder.DefaultHandler
路由的RouteAsync
方法,DefaultHandler
实际上也是继承自IRouter
RouteHandler
和MvcRouteHandler
都可以作为routeBuilder.DefaultHandler
,以提供Route
类实例化需要的参数。RouteHandler
的RouteAsync
方法直接给context.Handler
赋值从构造函数接收到的委托。MvcRouteHandler``RouteAsync
方法则先根据匹配到的路由从已注册的控制器中适配方法,然后得到actionDescriptor
,包含http上下文以及方法的基本信息,最后直接给context.Handler
赋值,MVC流程从invoker.InvokeAsync()
开始
public Task RouteAsync(RouteContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
var candidates = _actionSelector.SelectCandidates(context);
if (candidates == null || candidates.Count == 0)
{
_logger.NoActionsMatched(context.RouteData.Values);
return Task.CompletedTask;
}
var actionDescriptor = _actionSelector.SelectBestCandidate(context, candidates);
if (actionDescriptor == null)
{
_logger.NoActionsMatched(context.RouteData.Values);
return Task.CompletedTask;
}
context.Handler = (c) =>
{
var routeData = c.GetRouteData();
var actionContext = new ActionContext(context.HttpContext, routeData, actionDescriptor);
if (_actionContextAccessor != null)
{
_actionContextAccessor.ActionContext = actionContext;
}
var invoker = _actionInvokerFactory.CreateInvoker(actionContext);
if (invoker == null)
{
throw new InvalidOperationException(
Resources.FormatActionInvokerFactory_CouldNotCreateInvoker(
actionDescriptor.DisplayName));
}
return invoker.InvokeAsync();
};
return Task.CompletedTask;
}
路由注册
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
总结