Routing of ASP. NET Core [4]: Let's look at the RouterMiddleware middleware that implements routing,
Although ASP. the routing of the NET Core application is completed through the middleware RouterMiddleware, but the specific routing parsing function falls on the specified Router object, however, we still need to introduce this middleware from the perspective of code implementation. Before that, let's first understand a special feature. [This Article has been synchronized to ASP. NET Core framework secrets]
After the RouterMiddleware middleware entrusts the Router to complete the routing work, the parsed Routing Parameters are stored in the RouteContext context in the form of a RouteData object. However, RouteContext is the context created for the execution of the Router. After the route Parsing is completed, the lifecycle of the context also ends. Since the entire RouteContext context does not exist, how can I obtain this RouteData object in the subsequent steps of request processing?
Through the example of "register the ing between URL mode and HttpHandler", we know that we can call the extended method GetRouteData of HttpContext to obtain the RouteData object that contains all the route parameters of the element, this means that the RouteData originally attached to the RouteContext context will be appended to the HttpContext that represents the current request context, and the RouteData is the RoutingFeature feature. RoutingFeature is a general term for all types and corresponding objects that implement the IRoutingFeature interface. As shown in the following code snippet, this interface saves the RouteData that is finally appended to HttpContext through the RouteData attribute. The RoutingFeature class is the default implementer of this interface. Our RouterMiddleware uses this object by default.
1: public interface IRoutingFeature
2: {
3: RouteData RouteData { get; set; }
4: }
5:
6: public class RoutingFeature : IRoutingFeature
7: {
8: public RouteData RouteData { get; set; }
9: }
The following code snippet shows the complete logic of RouterMiddleware for processing requests. When creating a RouterMiddleware object, we need to specify a Router object and a LoggerFactory used to create a Logger. When the middleware starts to process the request, it will create a RouteContext context object based on the current HttpContext and use it as a parameter to call the RotueAsync method of the Router for Route resolution. If the request returned by the Handler attribute of RouteContext is processed after the route resolution ends, it means that the current request matches the registered route. In this case, the current request is sent to the processor for subsequent processing. Before that, it will propose RouteData from the RouteContext context, and then create a RoutingFeature object and attach it to HttpContext.
1: public class RouterMiddleware
2: {
3: private ILogger _logger;
4: private RequestDelegate _next;
5: private IRouter _router;
6:
7: public RouterMiddleware(RequestDelegate next, ILoggerFactory loggerFactory, IRouter router)
8: {
9: _next = next;
10: _logger = loggerFactory.CreateLogger<RouterMiddleware>();
11: _router = router;
12: }
13:
14: public async Task Invoke(HttpContext context)
15: {
16: RouteContext routeContext = new RouteContext(context);
17: routeContext.RouteData.Routers.Add(_router);
18: await _router.RouteAsync(routeContext);
19: if (null == routeContext.Handler)
20: {
21: _logger.LogDebug(1, "Request did not match any routes.");
22: await _next(context);
23: }
24: else
25: {
26: context.Features.Set<IRoutingFeature>(new RoutingFeature { RouteData = routeContext.RouteData})
27: await routeContext.Handler(context);
28: }
29: }
30: }
In addition to calling the extension method GetRouteData of HttpContext to obtain the RouteData object that encapsulates route parameters, we can call another extension method named GetRouteValue to directly obtain the value of a route parameter. In the code snippets shown below, we use relatively simple code to demonstrate the implementation of these two extensions.
1: public static class RoutingHttpContextExtensions
2: {
3: public static RouteData GetRouteData(this HttpContext context)
4: {
5: return context.Features.Get<IRoutingFeature>()?.RouteData;
6: }
7:
8: public static object GetRouteValue(this HttpContext context, string key)
9: {
10: return context.GetRouteData()?.Values[key];
11: }
12: }
Generally, we tend to call the extended method UseRouter of ApplicationBuilder to register the RouterMiddleware middleware. Specifically, we can choose to overload the following two UseRouter methods. If you call the first overload, we need to provide a specific Router object for the registered RouterMiddleware middleware. For the second overload, This Router object is actually created using RouteBuilder. When calling this method, we need to use this RouteBuilder to register the required route in the form of an Action <IRouteBuilder> object.
1: public static class RoutingBuilderExtensions
2: {
3: public static IApplicationBuilder UseRouter(this IApplicationBuilder builder, IRouter router)
4: {
5: return builder.UseMiddleware<RouterMiddleware>(new object[] { router });
6: }
7:
8: public static IApplicationBuilder UseRouter(this IApplicationBuilder builder, Action<IRouteBuilder> action)
9: {
10: RouteBuilder routeBuilder = new RouteBuilder(builder);
11: action(routeBuilder);
12: return builder.UseRouter(routeBuilder.Build());
13: }
14: }