UseRouting: Matches request to an endpoint.
UseEndpoints: Execute the matched endpoint.
It decouples the route matching and resolution functionality from the endpoint executing functionality, which until now was all bundled in with the MVC middleware.
This makes the ASP.NET Core framework more flexible and allows other
middlewares to act between UseRouting and UseEndpoints. That allows
those middlewares to utilize the information from endpoint routing,
for example, the call to UseAuthentication must go after
UseRouting, so that route information is available for authentication decisions and before UseEndpoints so that users are
authenticated before accessing the endpoints.
Update .NET 6
In ASP.NET Core 6, there’s no need to have explicit calls to UseRouting or UseEndpoints to register routes. UseRouting can still be used to specify where route matching happens, but UseRouting doesn’t need to be explicitly called if routes should be matched at the beginning of the middleware pipeline.
Depending on where app.Use is called in the pipeline, there may not be an endpoint:
app.Use(async (context, next) =>
{
Console.WriteLine("Before routing runs, endpoint is always null here");
Console.WriteLine($"Endpoint: {context.GetEndpoint()?.DisplayName ?? "null"}");
await next(context);
});
app.UseRouting();
app.Use(async (context, next) =>
{
Console.WriteLine("After routing runs, endpoint will be non-null if routing found a match.");
Console.WriteLine($"Endpoint: {context.GetEndpoint()?.DisplayName ?? "null"}");
await next(context);
});
app.MapGet("/", (HttpContext context) =>
{
Console.WriteLine("Runs when this endpoint matches");
Console.WriteLine($"Endpoint: {context.GetEndpoint()?.DisplayName ?? "null"}");
return "Hello World!";
}).WithDisplayName("/");
app.UseEndpoints(_ => { });
app.Use(async (context, next) =>
{
Console.WriteLine("Runs after UseEndpoints - will only run if there was no match.");
Console.WriteLine($"Endpoint: {context.GetEndpoint()?.DisplayName ?? "null"}");
await next(context);
});