This is the translation of official documents, Official documents are now not machine translated
https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/middleware/?view=aspnetcore-2.1

<https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/middleware/?view=aspnetcore-2.1>

What is Middleware(Middleware)?

Middleware is software assembled into application pipelines to handle requests and responses. Each component:

* Choose whether to pass the request to the next component in the pipeline.
* Work can be performed before and after calling the next component in the pipeline.
Request for delegation(Request delegates) Used to build request pipeline, Deal with eachHTTP request.

Request delegated useRun,Map andUse
Configuration by extension method. Individual request delegates can be inline anonymous( Called inline Middleware) Appoint, Or you can define it in a reusable class. These reusable classes and inline anonymous methods are middleware or middleware components. Each middleware component in the request process is responsible for calling the next component in the pipeline, If appropriate, Is responsible for link short circuit.

takeHTTP Module migration to middleware explainedASP.NET Core And previous versions(ASP.NET) Differences between request pipes in, More middleware examples are provided.

Use IApplicationBuilder Create middleware pipeline

ASP.NET Core The request process consists of a series of request delegates, As shown in the figure below( The execution process follows the black arrow):




Each delegate can perform actions before and after the next delegate. Delegates can also decide not to pass requests to the next delegate, This is called a short in the requesting pipe. Short circuit is usually desirable, Because it avoids unnecessary work. for example, Static file middleware can return a static file request, And short the rest of the pipe. Exception handling delegation needs to be called early in the pipeline, So they can catch the exception of the later pipeline.

The simplest is probablyASP.NET Core The application establishes a requested delegate, Process all requests. This case does not contain the actual request pipeline. Contrary, For eachHTTP All requests call an anonymous method.
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using
Microsoft.AspNetCore.Http; public class Startup { public void
Configure(IApplicationBuilder app) { app.Run(async context => { await
context.Response.WriteAsync("Hello, World!"); }); } }
First app.Run Commissioned termination pipeline.

There are the following codes:



Access through browser, It was found thatapp.Run Pipe terminated.



You can delegate multiple requests toapp.Use come together. next Parameter represents the next delegate in the pipeline.
( please remember, You can end the pipeline without calling the next parameter.) Operations can usually be performed before and after the next delegate, As shown in the following example:
public class Startup { public void Configure(IApplicationBuilder app) {
app.Use(async (context, next) => { await context.Response.WriteAsync(" Enter the first delegation
Before the next delegation\r\n"); // Call the next delegate in the pipeline await next.Invoke(); await
context.Response.WriteAsync(" End first delegate After the next delegation\r\n"); }); app.Run(async context
=> { await context.Response.WriteAsync(" Enter the second delegation\r\n"); await
context.Response.WriteAsync("Hello from 2nd delegate.\r\n"); await
context.Response.WriteAsync(" End second delegation\r\n"); }); } }
Using the browser to access the following results:



It can be seen that the execution order of the request delegation follows the above flowchart.

Be careful:
After the response is sent to the client, Do not callnext.Invoke. After response starts, YesHttpResponse Changes to will throw an exception.
for example, Set response header, Changes such as status codes will throw exceptions. In callnext Write response body after.

*
Possible protocol violation. for example, Write overcontent-length Length of content.

*
May break response content format. for example, takeHTML Footer writeCSS file.

HttpResponse.HasStarted It's a useful tip, Indicates whether response headers and/ Or body written.

order

stayStartup.Configure Method defines the order in which middleware components are called on requests, And the reverse order of the response. This sort is for security, Performance and functionality are critical.

Startup.Configure Method( As shown below) The following middleware components have been added:

* abnormal/ error handling
* Static file service
* identity authentication
* MVC public void Configure(IApplicationBuilder app) {
app.UseExceptionHandler("/Home/Error"); // Call first to catch exceptions //
thrown in the following middleware. app.UseStaticFiles(); // Return static
files and end pipeline. app.UseAuthentication(); // Authenticate before you
access // secure resources. app.UseMvcWithDefaultRoute(); // Add MVC to the
request pipeline. }
Code above,UseExceptionHandler Is the first middleware component added to the pipeline, So it captures any exceptions that occur in subsequent calls..

Static file middleware is called in advance in pipeline. So you can handle requests and short circuits, Without passing through the remaining components. Static file middleware does not provide authorization check.
Any documents provided by it, Includewwwroot The next documents are all public.

If the request is not processed by static file Middleware, It will be passed to theIdentity middleware(app.UseAuthentication).
Identity does not short-circuit unauthenticated requests. Although authentication request, But authorized( And refusal) Only inMVC Select specificRazor Occurs after page or controller and action.

To grant authorization( And refusal) Only inMVC Select specificRazor Page orController andAction After that.

The following example demonstrates the middleware sequence, The request of static file is processed by static file middleware before responding to compression middleware. Static files are not compressed in the order of Middleware.
Come fromUseMvcWithDefaultRoute OfMVC Response can be compressed.
public void Configure(IApplicationBuilder app) { app.UseStaticFiles(); //
Static files not compressed app.UseResponseCompression();
app.UseMvcWithDefaultRoute(); }
Use, Run, and Map

You can useUse,Run andMap To configureHTTP The Conduit.Use Method can make the pipe short circuit( Namely, Can not call the next request delegation).Run Method is an agreement,
And some middleware components may be exposed to theRun [Middleware] Method.Map*
Extend conventions used as branch pipes. The map branches the request pipeline according to the matching of the given request path, If the request path starts with the given path, Then branch.
public class Startup { private static void HandleMapTest1(IApplicationBuilder
app) { app.Run(async context => { await context.Response.WriteAsync("Map Test
1"); }); } private static void HandleMapTest2(IApplicationBuilder app) {
app.Run(async context => { await context.Response.WriteAsync("Map Test 2"); });
} public void Configure(IApplicationBuilder app) { app.Map("/map1",
HandleMapTest1); app.Map("/map2", HandleMapTest2); app.Run(async context => {
await context.Response.WriteAsync("Hello from non-Map delegate. <p>"); }); } }


The following table shows the http://localhost:19219 <http://localhost:19219> Requests and responses for:

request response
localhost:1234 Hello from non-Map delegate.
localhost:1234/map1 Map Test 1
localhost:1234/map2 Map Test 2
localhost:1234/map3 Hello from non-Map delegate.
When usedMap Time, The matching path segment will be fromHttpRequest.Path Delete in, And append each request toHttp Request.PathBase.

MapWhen Branch request pipeline according to the result of given predicate. Any type isFunc<HttpContext,bool> Can be used to map requests to new branches of the pipeline.
In the following example, Predicates are used to detect the existence of query string variable branches:
public class Startup { private static void HandleBranch(IApplicationBuilder
app) { app.Run(async context => { var branchVer =
context.Request.Query["branch"]; await context.Response.WriteAsync($"Branch
used = {branchVer}"); }); } public void Configure(IApplicationBuilder app) {
app.MapWhen(context => context.Request.Query.ContainsKey("branch"),
HandleBranch); app.Run(async context => { await
context.Response.WriteAsync("Hello from non-Map delegate. <p>"); }); } }


The following table shows using the above code http://localhost:19219 <http://localhost:19219> Requests and responses for:

request response
localhost:1234 Hello from non-Map delegate.
localhost:1234/?branch=1 Branch used = master
Map Support nesting, for example:
app.Map("/level1", level1App => { level1App.Map("/level2a", level2AApp => { //
"/level1/level2a" //... }); level1App.Map("/level2b", level2BApp => { //
"/level1/level2b" //... }); });
Map You can also match multiple clips at once, for example:
app.Map("/level1/level2", HandleMultiSeg);
Built in middleware

ASP.NET Core The following middleware components are included:

middleware describe
Authentication Provide authentication support
CORS Configure cross domain resource sharing
Response Caching Provide cache response support
Response Compression Provide response compression support
Routing Define and constrain request routes
Session Provide user session management
Static Files Service support for static file and directory browsing
URL Rewriting Middleware Used for rewriting Url, And will request redirection support
Write Middleware

Middleware is usually encapsulated in a class, And use extended methods for exposure. View the following Middleware, It sets the current requestedCulture:
public class Startup { public void Configure(IApplicationBuilder app) {
app.Use((context, next) => { var cultureQuery =
context.Request.Query["culture"]; if (!string.IsNullOrWhiteSpace(cultureQuery))
{ var culture = new CultureInfo(cultureQuery); CultureInfo.CurrentCulture =
culture; CultureInfo.CurrentUICulture = culture; } // Call the next
delegate/middleware in the pipeline return next(); }); app.Run(async (context)
=> { await context.Response.WriteAsync( $"Hello
{CultureInfo.CurrentCulture.DisplayName}"); }); } }
You can passCulture To test Middleware, for example http://localhost:19219/?culture=zh-CN
<http://localhost:19219/?culture=zh-CN>

The following code moves the middleware delegation to a class:
using Microsoft.AspNetCore.Http; using System.Globalization; using
System.Threading.Tasks; namespace Culture { public class
RequestCultureMiddleware { private readonly RequestDelegate _next; public
RequestCultureMiddleware(RequestDelegate next) { _next = next; } public Task
Invoke(HttpContext context) { var cultureQuery =
context.Request.Query["culture"]; if (!string.IsNullOrWhiteSpace(cultureQuery))
{ var culture = new CultureInfo(cultureQuery); CultureInfo.CurrentCulture =
culture; CultureInfo.CurrentUICulture = culture; } // Call the next
delegate/middleware in the pipeline return this._next(context); } } }
The following passageIApplicationBuilder Middleware exposed by extension method of:
using Microsoft.AspNetCore.Builder; namespace Culture { public static class
RequestCultureMiddlewareExtensions { public static IApplicationBuilder
UseRequestCulture( this IApplicationBuilder builder) { return
builder.UseMiddleware<RequestCultureMiddleware>(); } } }
The following code fromConfigure Call Middleware:
public class Startup { public void Configure(IApplicationBuilder app) {
app.UseRequestCulture(); app.Run(async (context) => { await
context.Response.WriteAsync( $"Hello
{CultureInfo.CurrentCulture.DisplayName}"); }); } }
Middleware should follow the principle of explicit dependency, By exposing its dependencies in its constructor. Middleware is built once in the application life cycle. If you need to share services with middleware in the request, See request dependencies below.

Middleware components can resolve dependency of dependency injection by constructing method parameters. UseMiddleware Other parameters can also be accepted directly.

Dependencies per request

Because middleware is built when the application starts, Not every request, So during each request, Scope lifecycle services used by middleware constructors are not shared with other dependency injection types.
If you have to share scope services between middleware and other types, Please add these services toInvoke Method's signature. Invoke Method can accept other parameters populated by dependency injection. for example:
public class MyMiddleware { private readonly RequestDelegate _next; public
MyMiddleware(RequestDelegate next) { _next = next; } public async Task
Invoke(HttpContext httpContext, IMyScopedService svc) { svc.MyProperty = 1000;
await _next(httpContext); } }