Endpoint routing ( Endpoint Routing
) first appeared in ASP.NET Core2.2
the ASP.NET Core3.0
promotion to a first-class citizen.
Endpoint Routing
Motivation
Before the emergence of endpoint routing, we generally define MVC middleware resolution routing at the end of the request processing pipeline. This approach means that in the processing pipeline, the middleware before the MVC middleware will not be able to obtain routing information.
Routing information is very useful for some middleware, such as CORS, authentication middleware (routing information may be used in the authentication process).
At the same time, endpoint routing extracts the endpoint concept, decouples routing matching logic, and request distribution.
Endpoint Routing
Middleware
Consists of a pair of middleware:
UseRouting
Add route matching to the middleware pipeline. The middleware looks at the set of endpoints defined in the application and selects the best match based on the request.UseEndpoints
Add endpoint execution to the middleware pipeline.MapGet
, AndMapPost
other methods connect the processing logic to the routing system; other methods connect the ASP.NET Core framework features to the routing system.MapRazorPages
for Razor PagesMapControllers
for controllersMapHub< THub>
for SignalRMapGrpcService< TService>
for gRPC
The middleware upstream of this pair of middleware: always cannot perceive Endpoint
;
the middleware between this pair of middleware will perceive the matched Endpoint
and have the ability to add processing logic; it
UseEndpoints
is an end-point middleware; if
there is no match, then UseEndpoints
After entering the middleware.
Placed UseRouting
, UseEndpoints
between authentication and authorization middleware:
perception endpoint information is matched; the scheduling Endpoint
before the application authorization policy.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
// Matches request to an endpoint.
app.UseRouting();
// Endpoint aware middleware.
// Middleware can use metadata from the matched endpoint.
app.UseAuthentication();
app.UseAuthorization();
// Execute the matched endpoint.
app.UseEndpoints(endpoints =>
{
// Configure the Health Check endpoint and require an authorized user.
endpoints.MapHealthChecks("/healthz").RequireAuthorization();
// Configure another endpoint, no authorization requirements.
endpoints.MapGet("/", async context =>
{
await context.Response.WriteAsync("Hello World!");
});
});
}
The /health
health check is defined above . The endpoint defines the IAuthorizeData
metadata and requires authentication before performing the health check.
We UseRouting
, UseEndpoints
add a little test code between: Perception endpoints:
app.Use(next => context =>
{
var endpoint = context.GetEndpoint();
if (endpoint is null)
{
return Task.CompletedTask;
}
Console.WriteLine($"Endpoint: {endpoint.DisplayName}");
if (endpoint is RouteEndpoint routeEndpoint)
{
Console.WriteLine("Endpoint has route pattern: " +
routeEndpoint.RoutePattern.RawText);
}
foreach (var metadata in endpoint.Metadata)
{
Console.WriteLine($"Endpoint has metadata: {metadata}");
}
return next(context);
});
When requesting /healthz
, I perceive the AuthorizeAttribute
metadata and
guess that if the authentication and authorization middleware is to /healthz
work properly, it will inevitably respond to this AuthorizeAttribute
metadata.
So flipping through the Github AuthorizationMiddleware 3.0 source code: I found that the request processing delegation really paid attention Endpoint
, and extracted the IAuthorizeData
authorization information in the metadata .
// ---- 截取自https://github.com/dotnet/aspnetcore/blob/master/src/Security/Authorization/Policy/src/AuthorizationMiddleware.cs-----
if (endpoint != null)
{
context.Items[AuthorizationMiddlewareInvokedWithEndpointKey] = AuthorizationMiddlewareWithEndpointInvokedValue;
}
var authorizeData = endpoint?.Metadata.GetOrderedMetadata<IAuthorizeData>() ?? Array.Empty<IAuthorizeData>();
var policy = await AuthorizationPolicy.CombineAsync(_policyProvider, authorizeData);
if (policy == null)
{
await _next(context);
return;
}
var policyEvaluator = context.RequestServices.GetRequiredService<IPolicyEvaluator>();
......
What the test code perceives is AuthorizeAttribute
indeed the realization of the IAuthorizeData
interface.
bingo, guess the source code verification.
in conclusion
Endpoint routing: Allows ASP.NET Core applications to determine the endpoints to be scheduled early in the middleware pipeline, so that subsequent middleware can use this information to provide functions that cannot be provided by the current pipeline configuration.
This makes the ASP.NET Core framework more flexible and strengthens the concept of endpoints. It decouples routing matching and parsing functions from endpoint scheduling functions.