ASP.NET Core的路由[4]:来认识一下实现路由的RouterMiddleware中间件
2016-12-23 08:26
766 查看
虽然ASP.NET Core应用的路由是通过RouterMiddleware这个中间件来完成的,但是具体的路由解析功能都落在指定的Router对象上,不过我们依然有必要以代码实现的角度来介绍一下这个中间件。在这之前,我们先来认识一个特殊的特性。[本文已经同步到《ASP.NET Core框架揭秘》之中]
让RouterMiddleware中间件委托Router完整整个路由工作之后,解析出来的路由参数会以一个RouteData对象的形式存储在RouteContext上下文中。但是RouteContext是为Router的执行建立的上下文,路由解析工作完成之后,这个上下文的生命周期也随着结束,既然整个RouteContext上下文都不存在了,请求处理的后续步骤如何获取这个RouteData对象呢?
通过《注册URL模式与HttpHandler的映射关系》的实例演示我们知道可以调用HttpContext的扩展方法GetRouteData来获取这个包含素所有路由参数的RouteData对象,这个意味着原本依附于RouteContext上下文的RouteData最终会被附加到代表当前请求上下文的HttpContext上,而具体承载这个RouteData的就是这个名为RoutingFeature的特性。RoutingFeature是我们对所有实现了IRoutingFeature接口的所有类型以及对应对象的统称。如下面的代码片段所示,这个接口通过属性RouteData来保存最终附加到HttpContext的RouteData。RoutingFeature类是这个接口的默认实现者,我们的RouterMiddleware默认情况下就是使用这个对象。
如下所示的代码片段体现了RouterMiddleware处理请求的完整逻辑。我们在创建一个RouterMiddleware对象的时候需要指定一个Router对象,以及一个用来创建Logger的LoggerFactory。当这个中间件开始处理请求的时候,它会根据当前HttpContext创建一个RouteContext上下文对象,并将其作为参数调用Router的RotueAsync方法进行路由解析。如果在路由解析结束之后通过RouteContext的Handler属性返回的请求处理存在,意味着当前请求与注册的路由匹配,在此情况下它会将当前请求交给这个处理器做后续处理。在这之前它会从RouteContext上下文中提出出RouteData,然后据此创建一个RoutingFeature对象并附加到HttpContext上面。
我们除了可以调用HttpContext的扩展方法GetRouteData得到封装了路由参数的RouteData对象之前,我们还可以调用另一个名为GetRouteValue发的扩展方法直接获取某个路由参数的值。在如下所示的代码片段中,我们采用比较简单代码展示了这两个扩展放的实现。
一般来说我们倾向于调用ApplicationBuilder的扩展方法UseRouter来注册RouterMiddleware中间件。具体来说,我们可以选择如下两个UseRouter方法重载。如果调用第一个重载,我们需要为注册的RouterMiddleware中间件提供一个具体的Router对象。对于第二个重载来说,这个Router对象实际上是利用RouteBuilder创建的,我们在调用这个方法的时候需要以Action<IRouteBuilder>对象的形式利用这个RouteBuilder注册所需的路由。
ASP.NET Core的路由[1]:注册URL模式与HttpHandler的映射关系
ASP.NET Core的路由[2]:路由系统的核心对象——Router
ASP.NET Core的路由[3]:Router的创建者——RouteBuilder
ASP.NET Core的路由[4]:来认识一下实现路由的RouterMiddleware中间件
ASP.NET Core的路由[5]:内联路由约束的检验
让RouterMiddleware中间件委托Router完整整个路由工作之后,解析出来的路由参数会以一个RouteData对象的形式存储在RouteContext上下文中。但是RouteContext是为Router的执行建立的上下文,路由解析工作完成之后,这个上下文的生命周期也随着结束,既然整个RouteContext上下文都不存在了,请求处理的后续步骤如何获取这个RouteData对象呢?
通过《注册URL模式与HttpHandler的映射关系》的实例演示我们知道可以调用HttpContext的扩展方法GetRouteData来获取这个包含素所有路由参数的RouteData对象,这个意味着原本依附于RouteContext上下文的RouteData最终会被附加到代表当前请求上下文的HttpContext上,而具体承载这个RouteData的就是这个名为RoutingFeature的特性。RoutingFeature是我们对所有实现了IRoutingFeature接口的所有类型以及对应对象的统称。如下面的代码片段所示,这个接口通过属性RouteData来保存最终附加到HttpContext的RouteData。RoutingFeature类是这个接口的默认实现者,我们的RouterMiddleware默认情况下就是使用这个对象。
[code] public interface IRoutingFeature
{
RouteData RouteData{ get; set;}
}
public class RoutingFeature : IRoutingFeature
{
public RouteData RouteData{ get; set;}
}
如下所示的代码片段体现了RouterMiddleware处理请求的完整逻辑。我们在创建一个RouterMiddleware对象的时候需要指定一个Router对象,以及一个用来创建Logger的LoggerFactory。当这个中间件开始处理请求的时候,它会根据当前HttpContext创建一个RouteContext上下文对象,并将其作为参数调用Router的RotueAsync方法进行路由解析。如果在路由解析结束之后通过RouteContext的Handler属性返回的请求处理存在,意味着当前请求与注册的路由匹配,在此情况下它会将当前请求交给这个处理器做后续处理。在这之前它会从RouteContext上下文中提出出RouteData,然后据此创建一个RoutingFeature对象并附加到HttpContext上面。
[code] public class RouterMiddleware
{
private ILogger _logger;
private RequestDelegate _next;
private IRouter _router;
public RouterMiddleware(RequestDelegate next, ILoggerFactory loggerFactory, IRouter router)
{
_next = next;
_logger = loggerFactory.CreateLogger<RouterMiddleware>();
_router = router;
}
public async Task Invoke(HttpContext context)
{
RouteContext routeContext = new RouteContext(context);
routeContext.RouteData.Routers.Add(_router);
await _router.RouteAsync(routeContext);
if (null == routeContext.Handler)
{
_logger.LogDebug(1, "Request did not match any routes.");
await _next(context);
}
else
{
context.Features.Set<IRoutingFeature>(new RoutingFeature{RouteData = routeContext.RouteData})
await routeContext.Handler(context);
}
}
}
我们除了可以调用HttpContext的扩展方法GetRouteData得到封装了路由参数的RouteData对象之前,我们还可以调用另一个名为GetRouteValue发的扩展方法直接获取某个路由参数的值。在如下所示的代码片段中,我们采用比较简单代码展示了这两个扩展放的实现。
[code] public static class RoutingHttpContextExtensions
{
public static RouteData GetRouteData(this HttpContext context)
{
return context.Features.Get<IRoutingFeature>()?.RouteData;
}
public static object GetRouteValue(this HttpContext context, string key)
{
return context.GetRouteData()?.Values[key];
}
}
一般来说我们倾向于调用ApplicationBuilder的扩展方法UseRouter来注册RouterMiddleware中间件。具体来说,我们可以选择如下两个UseRouter方法重载。如果调用第一个重载,我们需要为注册的RouterMiddleware中间件提供一个具体的Router对象。对于第二个重载来说,这个Router对象实际上是利用RouteBuilder创建的,我们在调用这个方法的时候需要以Action<IRouteBuilder>对象的形式利用这个RouteBuilder注册所需的路由。
[code] public static class RoutingBuilderExtensions
{
public static IApplicationBuilder UseRouter(this IApplicationBuilder builder, IRouter router)
{
return builder.UseMiddleware<RouterMiddleware>(new object[]{ router});
}
public static IApplicationBuilder UseRouter(this IApplicationBuilder builder, Action<IRouteBuilder> action)
{
RouteBuilder routeBuilder = new RouteBuilder(builder);
action(routeBuilder);
return builder.UseRouter(routeBuilder.Build());
}
}
ASP.NET Core的路由[1]:注册URL模式与HttpHandler的映射关系
ASP.NET Core的路由[2]:路由系统的核心对象——Router
ASP.NET Core的路由[3]:Router的创建者——RouteBuilder
ASP.NET Core的路由[4]:来认识一下实现路由的RouterMiddleware中间件
ASP.NET Core的路由[5]:内联路由约束的检验
相关文章推荐
- ADO.NET .net core2.0添加json文件并转化成类注入控制器使用 简单了解 iTextSharp实现HTML to PDF ASP.NET MVC 中 Autofac依赖注入DI 控制反转IOC 了解一下 C# AutoMapper 了解一下
- 在 ASP.NET Core 项目中实现小写的路由URL
- 在 ASP.NET Core 项目中实现小写的路由URL
- 认识 ASP.NET 3.5 MVC 路由 创建自定义路由
- ASP.NET中实现Flash与.NET的紧密集成(转,没看,有空研究一下)
- 在ASP.NET MVC中通过URL路由实现对多语言的支持
- 认识 ASP.NET 3.5 MVC 路由 在WebForm项目中使用路由
- ASP.NET路由系统实现原理:HttpHandler的动态映射
- ASP.NET MVC自定义路由 - 实现IRouteConstraint限制控制器名(转载)
- asp.net mvc 通过修改路由规则来实现页面的URL多参数传递
- ASP.NET 路由实现页面静态化
- ASP.NET 路由实现页面静态化
- Asp.net 路由系统的实现
- 认识 ASP.NET 3.5 MVC 路由解析分析
- 在ASP.NET MVC中通过URL路由实现对多语言的支持
- ASP.NET 路由实现页面静态化
- 认识 ASP.NET 3.5 MVC 路由 在WebForm项目中使用路由
- ASP.NET路由系统实现原理:HttpHandler的动态映射
- ASP.NET路由系统实现原理:HttpHandler的动态映射
- Asp.Net MVC 进阶篇:路由匹配 实现博客路径 和文章路径