preface
The last article mainly introduced the status of DotNetCore project. This article is actually used by us in developing our own projects, which is more suitable for practical applications. It is an in-depth use of middleware, not a simple Hello World. If you think this article is useful to you, you might as well click [recommend].
catalogue
- The role of Middleware
- Operation mode of Middleware
- The difference between Middleware and Filter
- What situation do we need middleware
- How to customize your Middleware
The role of Middleware
As we know, any web framework encapsulates http requests into a pipeline. Every request goes through a series of operations of the pipeline and finally reaches the code we write. Then middleware is a component in the application pipeline, which is used to intercept the request process and carry out some other processing and response. There can be many middleware. Each middleware can intercept the request in the pipeline, and it can decide whether to transfer the request to the next middleware.
asp.net core provides iaapplicationbuilder interface to register the middleware with the pipeline request of asp.net. Middleware is a typical AOP application. The following is an official Microsoft middleware pipeline request diagram:

As you can see, each middleware can operate before and after the request. After the request is processed, it is passed to the next request.
Operation mode of Middleware
By default, the execution sequence of middleware is executed according to the sequence registered in the public void configure (iaapplicationbuilder APP) {} method in the Startup.cs file. There are about three ways to register "middleware" in the pipeline
- app.Use(), provided natively by iaapplicationbuilder interface, used for registration, etc.
- app.Run() is an extension method. It requires a RequestDelegate delegate, which contains the context information of Http and has no next parameter, because it is always executed at the last step of the pipeline.
- app.Map() is also an extension method, similar to MVC routing. It is generally used to process some special request paths. For example: www.example.com/token, etc.
The above Run and Map are also used internally. It is an extension of the iaapplicationbuilder interface. If you think the names are not accurate enough, the following extension method is the authentic registration middleware and the most powerful. App. Usemiddleware < > (), yes, that's it. Why is it powerful? Because it not only provides the function of registering middleware, but also provides the function of dependency injection (DI). It will be used in most cases in the future.
The difference between Middleware and Filter
Students familiar with MVC framework should know that MVC also provides five filters for us to process the code to be executed before and after the request. They are authenticationfilter, authorizationfilter, actionfilter, exceptionfilter and resultfilter.
According to the description, we can see that the functions of middleware and filter are similar. What are the differences between them? Why build a middleware? In fact, the concerns of filters and middleware are different, that is, they do different things with different responsibilities.
Take chestnuts for example. The middleware is like the isinos blade, and the filter is like the wrath of the dragon and the soul sending staff of teregosa. A soldier takes the wrath of the dragon and the soul sending staff of teregosa to the battlefield to kill people. Although there are injuries, the damage of holding the staff is low, and it is less sexual.
As two AOP sharp tools, the Filter fits the business better. It focuses on the application itself. For example, you see ActionFilter and ResultFilter, which interact directly with your Action and ActionResult. Is it close to you? I have some, such as formatting my output results and verifying the data of my requested ViewModel, It must be Filter. It is a part of MVC. It can intercept some information of your Action context, which is not available in middleware.
What situation do we need middleware
So when to use middleware? My understanding is that some things that need to be done in the pipeline that have little to do with the business in our application can be used, such as authentication, Session storage, logging, etc. In fact, our asp.net core project itself already contains many middleware.
For example, when we create an asp.net core application, the default template is generated
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory) { app.UseDeveloperExceptionPage(); app.UseStaticFiles(); loggerFactory.AddConsole(); app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); }); }
Too lazy to download the source code, we use Reflector to view the source code:
//Extension method ` app. Usedeveloperexception page()` public static class DeveloperExceptionPageExtensions { // Methods public static IApplicationBuilder UseDeveloperExceptionPage(this IApplicationBuilder app) { if (app == null) { throw new ArgumentNullException("app"); } return UseMiddlewareExtensions.UseMiddleware<DeveloperExceptionPageMiddleware>(app, Array.Empty<object>()); } }
//Extension method ` app.UseStaticFiles()` public static class StaticFileExtensions { // Methods public static IApplicationBuilder UseStaticFiles(this IApplicationBuilder app) { if (app == null) { throw new ArgumentNullException("app"); } return UseMiddlewareExtensions.UseMiddleware<StaticFileMiddleware>(app, Array.Empty<object>()); } }
You can see that app. Usedeveloperexception page(), app.UseStaticFiles() and so on are implemented through middleware.
How to customize your Middleware
Background: the middleware used in our project is to share user information with other departments. Taking the platform and subsystem as an example, we are developing a subsystem in which user information, login, registration and other functions are placed on the platform. This is a cross multilingual system. The platform is developed in Java language. Users need to verify whether to log in when accessing some pages of the subsystem, and other pages do not need to verify whether to log in, Therefore, an authentication system is needed to replace the function of Identity.
Fortunately, Microsoft has provided us with a set of authentication middleware. Under the Microsoft.AspNetCore.Authentication namespace, we only need to expand and add our own functions. How to do it? Just look at the code.
According to the Convention, the middleware class needs to have an Invoke method. The signature is public async task Invoke (httpcontext) {}. The following is an example class of middleware:
public class RequestLoggerMiddleware { private readonly RequestDelegate _next; private readonly ILogger _logger; public RequestLoggerMiddleware(RequestDelegate next, ILoggerFactory loggerFactory) { _next = next; _logger = loggerFactory.CreateLogger<RequestLoggerMiddleware>(); } public async Task Invoke(HttpContext context) { _logger.LogInformation("Handling request: " + context.Request.Path); await _next.Invoke(context); _logger.LogInformation("Finished handling request."); } }
After understanding the above conventions, we begin to define our own middleware Class.
We need a flow chart to clarify the logical thinking, so that the thinking can be clearer when writing code.

A requirement of the platform is that after our subsystem exits, users should call an interface of the platform to inform them that they want to do some subsequent business.
OK, start rolling.
- First, create a platformauthenticationmiddleware, which inherits from the AuthenticationMiddleware class under Microsoft.AspNetCore.Authentication. Since AuthenticationMiddleware has implemented the Invoke function, we only need to override some of its methods. Wait, it seems that we still need some configurations, such as ReturnUrl in the flowchart, the Key value of the platform Cookie, the interface address of the platform to verify the user's legitimacy and other parameters.
- Create an Options class to configure settings. We name it PlatformAuthenticationOptions, inherit AuthenticationOptions, and implement the ioptions < T > interface. In this way, we can directly configure it in Startup.
- We only need to rewrite the CreateHandler method in AuthenticationMiddleware. The functions of our middleware can be realized in the Handler.
- Then create a Handler class for processing, named PlatformAuthenticationHandler, which inherits from authenticationhandler < Options > and is used to process calls in requests.
At this point, the classes required by our core have been established, and the rest is the filling code.
- Override the HandleAuthenticateAsync() method in PlatformAuthenticationHandler to control the main process.
- Rewrite the FinishResponseAsync() method in PlatformAuthenticationHandler to store the Session.
- Override the HandleSignOutAsync() method in the PlatformAuthenticationHandler to control logout, because after the user logs out, we need to notify the platform to do some other operations.
- Override the handleuuthorizedasync() method in PlatformAuthenticationHandler to perform unauthenticated operations.
Finally, we need an extension class to register our middleware with the extension method into the pipeline.
public static class MiddlewareExtensions { public static IApplicationBuilder UsePlatformAuthentication(this IApplicationBuilder app) { if (app == null) { throw new ArgumentNullException(nameof(app)); } return app.UseMiddleware<PlatformAuthenticationMiddleware>(); } public static IApplicationBuilder UsePlatformAuthentication(this IApplicationBuilder app, CookieAuthenticationOptions options) { if (app == null) { throw new ArgumentNullException(nameof(app)); } if (options == null) { throw new ArgumentNullException(nameof(options)); } return app.UseMiddleware<PlatformAuthenticationMiddleware>(Options.Create(options)); } }
In Startup, it is app.UsePlatformAuthentication()
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { loggerFactory.AddConsole(Configuration.GetSection("Logging")); //Registering PlatformAuthentication Middleware app.UsePlatformAuthentication(new PlatformAuthenticationOptions() { UserSessionStore = new UserSessionStore(), }); app.UseMvc(); }
Now, the implementation of our middleware core business process has come out. I don't have much space to paste the code, which will affect reading. Friends interested in the specific implementation can go to the following address to view the code and have comments on the specific process.
Sample source code: https://github.com/yuleyule66/PlatformAuthMiddleware