Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to use ASP.NET Core Middleware Middleware

2025-02-24 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

This article will explain in detail how to use the ASP.NET Core middleware Middleware. The editor thinks it is very practical, so I share it for you as a reference. I hope you can get something after reading this article.

Middle ware

First, borrow a picture from Microsoft's official documentation:

As you can see, middleware is actually a component configured in the HTTP request pipeline to handle requests and responses. It can:

Decide whether to pass the request to the next middleware in the pipeline

Operations can be performed before and after the next middleware processing in the pipe

In addition, the registration of middleware is sequential, so we must pay attention to it when writing code.

Middleware pipeline Run

This method adds a middleware to the HTTP request pipeline and identifies the middleware as the end of the pipeline, which is called terminal middleware. That is, the middleware is the end of the pipe, and the middleware registered after the middleware will never be executed. Therefore, this method is generally only written at the end of the Configure method.

Public class Startup {public void Configure (IApplicationBuilder app) {app.Run (async context = > {await context.Response.WriteAsync ("Hello, World!");});} Use

Use this method to quickly register an anonymous middleware

Public class Startup {public void Configure (IApplicationBuilder app) {app.Use (async (context, next) = > {/ / the operation before the next middleware processing: Console.WriteLine ("Use Begin"); await next () / / Console.WriteLine ("Use End");}) after the completion of the next middleware processing;}}

Note:

1. If you want to send the request to the next middleware in the pipe, be sure to call next.Invoke / next (), otherwise the pipe will be short-circuited and the subsequent middleware will not be executed

two。 In middleware, if you have already started sending Response to the client, do not call next.Invoke / next () and do not make any changes to Response, otherwise an exception will be thrown.

3. Context.Response.HasStarted can be used to determine whether the response has started.

The following are all incorrect code writing

Error 1:

Public class Startup {public void Configure (IApplicationBuilder app) {app.Use (async (context, next) = > {await context.Response.WriteAsync ("Use"); await next ();}) App.Run (context = > {/ / since the middleware above has already started Response, changing Response Header here will throw an exception context.Response.Headers.Add ("test", "test"); return Task.CompletedTask;});}}

Error 2:

Public class Startup {public void Configure (IApplicationBuilder app) {app.Use (async (context, next) = > {await context.Response.WriteAsync ("Use"); / / even if next.Invoke / next () is not called, you cannot change Response after Response starts context.Response.Headers.Add ("test", "test");}) }} UseWhen

Through this method, pipe branches are created for different logical conditions. It is important to note that:

After entering the pipe branch, if there is no pipe short circuit or terminal middleware in the pipe branch, it will return to the main pipe again.

When using PathString, the path must start with "/" and only one'/ 'character is allowed

Support nesting, that is, nesting UseWhen in UseWhen, etc.

Support to match multiple segments at the same time, such as / get/user

Public class Startup {public void Configure (IApplicationBuilder app) {/ get or / get/xxx will enter the pipeline branch app.UseWhen (context = > context.Request.Path.StartsWithSegments ("/ get"), app = > {app.Use (async (context, next) = > {Console.WriteLine ("UseWhen:Use"); await next () ); app.Use (async (context, next) = > {Console.WriteLine ("Use"); await next ();}); app.Run (async context = > {Console.WriteLine ("Run"); await context.Response.WriteAsync ("Hello World!");}) }}

When accessing / get, the output is as follows:

UseWhen:Use

Use

Run

If you find the output twice, don't panic, see if the browser sent two requests, / get and / favicon.ico.

Map

Through this method, pipe branches are created for different request paths. It is important to note that:

Once you enter the pipe branch, you will not return to the main pipe.

When using this method, the matching path is removed from the HttpRequest.Path and appended to the HttpRequest.PathBase.

The path must start with "/" and cannot have only one'/ 'character

Support for nesting, that is, nesting Map, MapWhen in Map (we'll talk about it next), etc.

Support to match multiple segments at the same time, such as / post/user

Public class Startup {public void Configure (IApplicationBuilder app) {/ / access / get will enter the pipeline branch / / access / get/xxx will enter the pipeline branch app.Map ("/ get", app = > {app.Use (async (context, next) = > {Console.WriteLine ("Map get: Use") Console.WriteLine ($"Request Path: {context.Request.Path}"); Console.WriteLine ($"Request PathBase: {context.Request.PathBase}"); await next ();}); app.Run (async context = > {Console.WriteLine ("Map get: Run") Await context.Response.WriteAsync ("Hello World!");}) / / access / post/user will enter the pipeline branch / / access / post/user/xxx will enter the pipeline branch app.Map ("/ post/user") App = > {/ / access / post/user/student will enter the pipeline branch / / access / post/user/student/1 will enter the pipeline branch app.Map ("/ student") App = > {app.Run (async context = > {Console.WriteLine ("Map / post/user/student: Run") Console.WriteLine ($"Request Path: {context.Request.Path}"); Console.WriteLine ($"Request PathBase: {context.Request.PathBase}"); await context.Response.WriteAsync ("Hello World!");};}) App.Use (async (context, next) = > {Console.WriteLine ("Map post/user: Use"); Console.WriteLine ($"Request Path: {context.Request.Path}"); Console.WriteLine ($"Request PathBase: {context.Request.PathBase}"); await next () }); app.Run (async context = > {Console.WriteLine ("Map post/user: Run"); await context.Response.WriteAsync ("Hello World!");}}

When you visit / get/user, the output is as follows:

Map get: Use

Request Path: / user

Request PathBase: / get

Map get: Run

When you visit / post/user/student/1, the output is as follows:

Map / post/user/student: Run

Request Path: / 1

Request PathBase: / post/user/student

It's up to you to try the rest!

MapWhen

Similar to Map, except that MapWhen does not create pipe branches based on paths, but based on logical conditions. Notes are as follows:

Once you enter the pipe branch, you will not return to the main pipe.

When using PathString, the path must start with "/" and only one'/ 'character is allowed

HttpRequest.Path and HttpRequest.PathBase don't have special treatment like Map does.

Support nesting, that is, nesting MapWhen, Map, etc., in MapWhen

Support to match multiple segments at the same time, such as / get/user

Public class Startup {public void Configure (IApplicationBuilder app) {/ get or / get/xxx will enter the pipeline branch app.MapWhen (context = > context.Request.Path.StartsWithSegments ("/ get"), app = > {app.MapWhen (context = > context.Request.Path.ToString (). Contains ("user"), app = > {app.Use (async (context)) Next) = > {Console.WriteLine ("MapWhen get user: Use") Await next ();}); app.Use (async (context, next) = > {Console.WriteLine ("MapWhen get: Use"); await next ();}) App.Run (async context = > {Console.WriteLine ("MapWhen get: Run"); await context.Response.WriteAsync ("Hello World!");}

When you visit / get/user, the output is as follows:

MapWhen get user: Use

As you can see, even if the pipe branch does not have terminal middleware, it will not return to the main pipe.

Run & Use & UseWhen & Map & Map

I suddenly came into contact with 4 similar named API related to middleware pipes. I don't know if you have fainted. It doesn't matter. Let me sum it up for you:

Run is used to register terminal middleware, Use is used to register anonymous middleware, and UseWhen, Map, MapWhen are used to create pipeline branches.

After UseWhen enters the pipe branch, if there is no short circuit or terminal middleware in the pipe branch, it will return to the main pipe. Once Map and MapWhen enter the pipe branch, they will never return to the main pipe anyway.

UseWhen and MapWhen create pipe branches based on logical conditions, while Map creates pipe branches based on request paths and processes HttpRequest.Path and HttpRequest.PathBase.

Write middleware and activate

Run and Use, which have already been mentioned above, will not be repeated.

Convention-based middleware

"the agreement is greater than the configuration". Let's start with three chapters:

1. Has a common (public) constructor that contains at least one parameter of type RequestDelegate

two。 Having a public method named Invoke or InvokeAsync must contain a method parameter of type HttpContext, which must be located at the location of the first parameter, and the method must return a Task type.

3. Other parameters in the constructor can be populated either by dependency injection (DI) or by passing parameters in UseMiddleware.

When populated by DI, only the DI parameters of Transient and Singleton can be received. This is because the middleware is constructed at the start of the application (not on request), so when the Scoped parameter appears, the life cycle of the DI parameter in the constructor is not shared with others, and if you want to share, you must add the Scoped DI parameter to Invoke/InvokeAsync for use.

When passing parameters through UseMiddleware, there is no requirement for the order of DI parameters and non-DI parameters in the constructor, and there is no requirement for the order of parameters passed into UseMiddleware, but I recommend putting non-DI parameters before and DI parameters after. (this piece feels like Microsoft is doing a good job.)

Other parameters of 4.Invoke/InvokeAsync can also be populated with dependency injection (DI) to receive DI parameters of Transient, Scoped, and Singleton.

A simple middleware is as follows:

Public class MyMiddleware {/ / is used to call the next middleware private readonly RequestDelegate _ next; public MyMiddleware (RequestDelegate next, ITransientService transientService, ISingletonService singletonService) {_ next = next in the pipeline. } public async Task InvokeAsync (HttpContext context, ITransientService transientService, IScopedService scopedService, ISingletonService singletonService) {/ / the operation before the next middleware processing Console.WriteLine ("MyMiddleware Begin"); await _ next (context); / / the operation Console.WriteLine ("MyMiddleware End") after the completion of the next middleware processing }}

You can then add it to the pipe through the UseMiddleware method

Public class Startup {public void Configure (IApplicationBuilder app) {app.UseMiddleware ();}}

However, it is generally not recommended to use UseMiddleware directly, but to encapsulate it in an extension method

Public static class AppMiddlewareApplicationBuilderExtensions {public static IApplicationBuilder UseMy (this IApplicationBuilder app) = > app.UseMiddleware ();} public class Startup {public void Configure (IApplicationBuilder app) {app.UseMy ();}} factory-based middleware

Advantages:

Activate as requested. That is to say, the above convention-based middleware instance is singleton, but the factory-based middleware can set the life cycle of the middleware instance during dependency injection.

Strongly typed middleware (because it implements interface IMiddleware)

The implementation of this method is based on IMiddlewareFactory and IMiddleware. Let's first take a look at the interface definition:

Public interface IMiddlewareFactory {IMiddleware? Create (Type middlewareType); void Release (IMiddleware middleware);} public interface IMiddleware {Task InvokeAsync (HttpContext context, RequestDelegate next);}

Have you ever wondered how UseMiddleware works when we call it? In fact, the UseMiddleware extension method first checks whether the middleware implements the IMiddleware interface. If so, use the IMiddlewareFactory instance registered in the container to parse the instance of the IMiddleware (now you know why it's called "factory-based middleware"). If not, then the middleware logic based on convention is used to activate the middleware.

Note that factory-based middleware is generally registered as a Scoped or Transient service in the service container of the application.

In this way, we can safely inject Scoped services into the constructor of the middleware.

Next, let's implement a factory-based middleware:

Public class YourMiddleware: IMiddleware {public async Task InvokeAsync (HttpContext context, RequestDelegate next) {/ / the operation before the next middleware processing Console.WriteLine ("YourMiddleware Begin"); await next (context); / / the operation Console.WriteLine ("YourMiddleware End") after the next middleware processing is completed;}} public static class AppMiddlewareApplicationBuilderExtensions {public static IApplicationBuilder UseYour (this IApplicationBuilder app) = > app.UseMiddleware ();}

Then, add middleware dependency injection to ConfigureServices

Public class Startup {public void ConfigureServices (IServiceCollection services) {services.AddTransient ();}}

Finally, use middleware in Configure

Public class Startup {public void Configure (IApplicationBuilder app) {app.UseYour ();}}

Microsoft provides the default implementation of IMiddlewareFactory:

Public class MiddlewareFactory: IMiddlewareFactory {/ / The default middleware factory is just an IServiceProvider proxy. / / This should be registered as a scoped service so that the middleware instances / / don't end up being singletons. / / the default middleware factory is only a proxy for IServiceProvider / / the factory should be registered as a Scoped service so that the middleware instance does not become a singleton private readonly IServiceProvider _ serviceProvider; public MiddlewareFactory (IServiceProvider serviceProvider) {_ serviceProvider = serviceProvider;} public IMiddleware? Create (Type middlewareType) {return _ serviceProvider.GetRequiredService (middlewareType) as IMiddleware;} public void Release (IMiddleware middleware) {/ / The container owns the lifetime of the service / / DI container to manage the lifecycle of the service}}

As you can see, the factory used the DI container to parse out the service instance's. Therefore, when using factory-based middleware, it is impossible to pass parameters to the constructor of the middleware through UseMiddleware.

Convention-based middleware VS factory-based middleware

Convention-based middleware instances are all Singleton;, while factory-based middleware instances can be Singleton, Scoped, and Transient (of course, registration as Singleton is not recommended)

The convention-based middleware instance constructor can pass parameters through dependency injection or UseMiddleware, while factory-based middleware can only pass parameters through dependency injection.

Convention-based middleware instances can add more dependency injection parameters to Invoke/InvokeAsync, while factory-based middleware can only be implemented according to the interface definition of IMiddleware.

This is the end of this article on "how to use ASP.NET Core middleware Middleware". I hope the above content can be of some help to you, so that you can learn more knowledge. if you think the article is good, please share it for more people to see.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report