A few days ago, .NET Core3.1 was released, so I upgraded a basic general system of the company, and deleted several basic modules. Of course, these basic modules are not related to .NET Core3.1, including the payment module. The upgrade is complete. Hou Jingwen (colleague) asked me that you deleted the payment? I said yes, I didn’t think about how to add it (I don’t think it is very good at the moment, I need to redesign it).

The story starts here

When thinking about payment, I think about how to introduce payment SDK directly into the system, and there can be a series of payment routes. What I need to consider is if I create a response to the specified address, so I started to think about how to achieve my purpose Middleware, Use, Run, Map ???

Advanced routing

Routing is responsible for mapping request URIs to endpoints and dispatching incoming requests to those endpoints. Routes are defined in the application and configured when the application starts. Routes can choose to extract values ​​from the URL contained in the request, which can then be used to process the request. By using routing information in the application, routing can also generate URLs that map to endpoints.

In ASP.NET Core 2.1 and earlier, routing is handled by implementing an interface that maps an IRouter incoming URL to a handler. Generally, you will directly rely on MvcMiddleware to add an implementation at the end of the middleware pipeline, rather than directly implementing the interface. Once the request arrives at MvcMiddleware, a route is applied to determine the controller and action corresponding to the incoming request URL path.

The request then passed through various MVC filters before executing the handler. These filters form another “pipe”, reminiscent of a middleware pipeline, and in some cases have to replicate the behavior of some middleware. A typical example is CORS policy. In order to implement different CORS policies for each MVC operation and other “branches” of the middleware pipeline, a certain degree of internal repetition is required.

“Branch” middleware pipelines are often used for “pseudo-routing”. Extension methods like Map () in the middleware pipeline will allow you to conditionally execute some middleware when the incoming path has a given prefix.

As follows:

Copy       app.Map("/order", app => app.Run(async context =>
                  await context.Response.WriteAsync("Order");

In this case, the Run () method is the “terminal” middleware because it returns a response. But in a sense, the entire Map branch corresponds to the “endpoint” of the application.

In ASP.NET Core 2.2, endpoint routing was introduced as a new routing mechanism for MVC controllers. This implementation is essentially an internal implementation of MvcMiddleware.

Using Map () in ASP.NET Core 2.x

Let’s customize a middleware. The middleware returns a direct response instead of continuing to execute the _next delegate, a very basic middleware.

Copy    public class ApiEndpointMiddleware
        private readonly RequestDelegate _next;

        public ApiEndpointMiddleware(RequestDelegate next)
            _next = next;

        public async Task InvokeAsync(HttpContext context)
            context.Response.StatusCode = 200;

            await context.Response.WriteAsync("Order");


In ASP.NET Core 2.x, this middleware can be accessed by specifying a route using an extension method to include it in the middleware pipeline of Startup.cs

Copypublic void Configure(IApplicationBuilder app)

    app.Map("/order", app => app.UseMiddleware<ApiEndpointMiddleware>()); versionApp.UseMiddleware<VersionMiddleware>()); 


When we visit the / order or / order / 1 route, we will get the response returned by the custom middleware.

Turn middleware into endpoint routing

In ASP.NET Core 3.0, we use endpoint routing, so the routing step is separate from the invocation of the endpoint. In practice, this means we have two middlewares:

  • EndpointRoutingMiddleware The actual route, which calculates which endpoint will be called for the specified request URL path.
  • EndpointMiddleware The endpoint of all calls.

They are added at two different points in the middleware pipeline because they serve two different roles. In general, what we want is that the routing middleware is in the pipeline in advance so that subsequent middleware can access information about the endpoints that will execute. The invocation of the endpoint should be made at the end of the pipeline.

As follows:

Copy public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
            if (env.IsDevelopment())




            app.UseEndpoints(endpoints =>


The UseRouting () extension method adds EndpointRoutingMiddleware to the pipeline, while the UseEndpoints () extension method adds EndpointMiddleware to the pipeline. UseEndpoints () actually registers the location of all endpoints for the application.

So how do we map our custom middleware with endpoint routing?

Conceptually, our UseEndpoints () uses / OrderURL as the matching path to move the registration of the “order” endpoint into the call:

Copy         endpoints.MapControllers();

In our implementation for ASP.NET Core 2.x above, we will match endpoint routes such as / order, / order / 123, etc.



This will match both / order / order / 1 but not / order / status / 1. It is much more powerful than previous versions.

In the previous example, we provided a display name (mainly used for debugging purposes), but we can attach other information, such as authorization policy or CORS policy, and other middleware can query this information. E.g:

Copy     app.UseEndpoints(endpoints =>

We added CORS policies (AllowAllHosts) and authorization policies (AdminOnly) to the endpoint. When a request to the endpoint arrives, take appropriate action before executing the endpoint.

















Orignal link: