Preface
This article is what we actually use in developing our own projects. It is more suitable for practical applications. It can be regarded as an in-depth use of middleware, not a simple Hello World.
The role of middleware
We know that any web framework encapsulates http requests into a pipeline, and each request goes through the pipeline. A series of operations finally arrive at the code we wrote. Then middleware is a component in the application pipeline that is used to intercept the request process and perform some other processing and response. There can be many middlewares, and each middleware can intercept requests in the pipeline, and it can decide whether to transfer the request to the next middleware.
asp.net core provides the IApplicationBuilder interface to register middleware into asp.net pipeline requests. Middleware is a typical AOP application.
Each middleware can operate before and after the request. After the request processing is completed, it is passed to the next request.
How middleware runs
By default, the execution order of middleware is based on the order registered in the public void Configure(IApplicationBuilder app){} method in the Startup.cs file. .
There are about 3 ways to register "middleware" in the pipeline
1.app.Use(), the IApplicationBuilder interface is provided natively, and it is used for registration, etc. .
2.app.Run() is an extension method. It requires a RequestDelegate delegate, which contains Http context information. There is no next parameter because it is always executed in the last step of the pipeline.
3.app.Map() is also an extension method, similar to MVC routing. It is generally used for processing some special request paths. For example: www.example.com/token etc.
The above Run and Map also call Use internally, which is an extension of the IApplicationBuilder interface. If you think the name is not accurate enough, then the following extension method is the authentic registration middleware, and it is also the most powerful. of.
app.UseMiddleware<>(), yes, that’s it. Why is it said to be powerful? Because it not only provides the function of registering middleware, but also provides the function of dependency injection (DI), which will be used in most situations in the future.
The difference between middleware and filter
Students who are familiar with the MVC framework should know that MVC also provides 5 major filters that we can use to process requests and need to be executed before and after code. They are AuthenticationFilter, AuthorizationFilter, ActionFilter, ExceptionFilter, and ResultFilter.
According to the description, it can be seen that the functions of middleware and filters are similar, so what is the difference between them? Why build another middleware?
In fact, filters and middleware have different focuses, which means they have different responsibilities and do different things.
For example, the middleware is like the Warglaive of Azzinoth, the filter is like the Wrath of the Dragon, Tarecgosa's Soul Staff, and you, a warrior, hold the Wrath of the Dragon. Legosa's soul-carrying staff goes to the battlefield to kill people. Although it does damage, the damage you do with the staff is low, and the attributes are reduced.
As two AOP tools, the filter is more suitable for the business. It focuses on the application itself. For example, if you look at ActionFilter and ResultFilter, they directly interact with your Action and ActionResult. Is it away from you? It feels very close. Then I have some things to do, such as formatting my output results and performing data verification on my requested ViewModel. I must use Filter. It is part of MVC. It can intercept some information about your Action context, but middleware does not have this ability.
When do we need middleware?
So, when should we use middleware? My understanding is that some things that need to be done in the pipeline that have little to do with the business can be used in our applications, such as authentication, session storage, logging, etc. In fact, our asp.net core project itself already contains a lot of middleware.
For example, when we create a new asp.net core application, among the templates generated by default
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?}"); }); }
I am too lazy to download the source code , we use Reflector to view the source code:
//扩展方法`app.UseDeveloperExceptionPage();` 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>()); } }
//扩展方法`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 app.UseDeveloperExceptionPage(), app.UseStaticFiles(), etc. All are implemented through middleware.
How to customize your own middleware
Background: The scenario where middleware is used in our project is that we need to share user (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-multi-language system. The platform is developed in Java language. Users access the subsystem. Some pages need to verify whether you are logged in, and other pages do not need to verify whether you are logged in, so an identity verification system is needed to replace the Identity function.
幸运的是微软已经给我们提供了一套身份验证的中间件,在Microsoft.AspNetCore.Authentication命名空间下,我们只需要拓展,添加自己的功能就行了 。具体怎么做呢?直接看代码吧。
根据约定俗成,中间件类需要有一个Invoke方法,签名是public async Task Invoke(HttpContext context){},下面是一个中间件的示例类:
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."); } }
了解了上面的约定之后,我们就开始定义我们自己的中间件Class。
我们需要一个流程图来理清逻辑思路,以便于写代码的时候思路更加的清晰。
平台有一个要求就是,用户在我们子系统退出之后,要调用平台的一个接口通知他们,他们要做一些后续的业务。
OK,开始撸码。
首先创建一个PlatformAuthoricationMiddleware,它继承于Microsoft.AspNetCore.Authentication下的类AuthenticationMiddleware,由于AuthenticationMiddleware已经实现了Invoke功能,所以我们只需要重写(override)它里面的一些方法就可以了。等等,我们好像还需要一些配置,比如流程图中的ReturnUrl,平台的Cookie的Key值,平台验证用户合法性的接口地址等参数。
建立一个Options类进行配置的设置,我们取名字为:PlatformAuthenticationOptions,继承AuthenticationOptions,并且实现掉IOptions
我们只需要重写AuthenticationMiddleware中的CreateHandler方法就行了,在Handler中可以实现掉我们中间件的功能。
然后创建一个处理的Handler类,取名为PlatformAuthenticationHandler,继承于AuthenticationHandler
至此,我们的核心需要的类已经建立完了,剩下的就是填充代码。
1.在PlatformAuthenticationHandler中重写HandleAuthenticateAsync()方法 , 进行主流程的控制。
2.在PlatformAuthenticationHandler中重写FinishResponseAsync()方法,进行Session的存储操作。
3.在PlatformAuthenticationHandler中重写HandleSignOutAsync()方法,进行登出的控制,因为用户登出之后我们要通知平台做一些其他操作。
4.在PlatformAuthenticationHandler中重写HandleUnauthorizedAsync()方法,进行未认证操作。
最后,我们需要一个扩展类来把我们的中间件以扩展方法注册到管道当中去 。
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)); } }
在Startup中就是app.UsePlatformAuthentication()
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { loggerFactory.AddConsole(Configuration.GetSection("Logging")); //注册PlatformAuthentication中间件 app.UsePlatformAuthentication(new PlatformAuthenticationOptions() { UserSessionStore = new UserSessionStore(), }); app.UseMvc(); }
现在,我们的中间件核心业务流程的实现已经出来了,我就不大篇幅的粘贴代码了,会影响阅读,感兴趣具体实现的朋友可以去下面的地址查看代码,有具体流程的注释。
以上就是本文的全部内容,希望对大家的学习有所帮助,更多浅谈ASP.NET Core 中间件详解及项目实战相关文章请关注PHP中文网!