Asp.Net Core Middleware

What is the middleware (Middleware)?

Middleware is assembled to the conduit application software to handle requests and responses. Each component:

  • Choose whether to pass the request to the next pipeline component.
  • You can call before the next component in the pipeline and after implementation.

Delegates the request (Request delegates) for constructing the request pipeline, each HTTP request processing.

Use delegation request Run, Mapand Useis configured extension method. Separate request can delegate inline anonymous method (referred to as inline middleware) is specified, or it may be defined in the reusable class. These reusable classes and anonymous method is inline middleware, or a middleware component. Each middleware component requests processes are responsible for calling the next component in the pipeline, if appropriate, is responsible for linking short-circuit.

HTTP module to migrate the middleware explains the differences between the previous version and ASP.NET Core (ASP.NET) in the request pipeline, middleware and provides additional examples.

Use IApplicationBuilder create middleware pipeline

ASP.NET Core request process by a series of requests and entrusted, as shown (black arrows execution flow follows):

 

Each delegate can delegate and before the next operation after execution. Delegate may also decide not to delegate a request to the next, which is called a short-circuit conduit request. Short circuit is usually preferable because it avoids unnecessary work. For example, the middleware static files may return the request for a static file, the short-circuit and the rest of the pipe. You need to call exception handling pipeline commissioned in early so they can catch exceptions behind pipe.

The easiest is probably ASP.NET Core application request to establish a commission to handle all the requests. This case does not contain the actual request pipeline. Instead, for each HTTP request to 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!");
        });
    }
}

The first  app.Run commission expires pipeline.

The following code:

Access through the browser and found that in the first app.Runtermination of the pipeline.

You can delegate the request to a plurality of app.Usejoined together. nextParameter indicates a delegate conduit. (Remember, you can not call the next parameter to the end of the line.) Can usually be commissioned before and after the next operation is performed in the following example:

 

public  class the Startup 
{ 
    public  void the Configure (IApplicationBuilder App) 
    { 
        app.Use ( the async (context, Next) => 
            { 
                the await context.Response.WriteAsync ( " before entering the next delegate performing a first delegate \ R & lt \ n- " );
                 // call the next pipe delegate 
                the await next.Invoke ();
                 the await context.Response.WriteAsync ( " after the end of the first delegate to the next delegate \ R & lt \ n- " ); 
            }); 
            app.run ( the async context => 
            { 
                the awaitcontext.Response.WriteAsync ( " into the second delegate \ R & lt \ n- " );
                 the await context.Response.WriteAsync ( " the Hello from 2nd \ R & lt \ n-the delegate. " );
                 the await context.Response.WriteAsync ( " end of the second a delegate \ R & lt \ n- " ); 
            }); 
    } 
}

Use a browser to access the following results:

 

It can be seen that the order of execution of the request delegation of following the above flow chart.

Note: The
response is sent back to the client, do not call next.Invoke. After the start of the response, changes to the HttpResponse will throw an exception. For example, in response to setting the first status code and other changes will throw an exception. In the call nextafter writing the response body.

  • It may lead to protocol violations. For example, writing over content-lengththe content length.

  • It may destroy the contents of the response format. For example, the HTML footer write CSS file.

HttpResponse.HasStarted is a useful tips, sending a response indicating whether the head and / or written text.

order

In Startup。Configureorder to add a middleware component calls a method defined in their order, and in reverse order in response to the request. This ordering is essential for safety, performance and functionality.

Startup.ConfigureThe method (shown below) were added the following middleware components:

  1. Exception / Error Handling
  2. Static files
  3. Authentication
  4. 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.
}

The above code, UseExceptionHandleris added to the first conduit in a middleware component, so it captures any abnormality occurs in later calls.

Intermediate file called a static pipe in advance, it is possible to process the request and short-circuit, without passing through the remainder of the assembly. Static files middleware does not provide authorization checks. Any documents provided by including under wwwroot files are public.

If the request is not a static document processing middleware, which will be passed to the implementation of Identity Authentication middleware (app.UseAuthentication). Identity does not make unauthenticated request a short circuit. Although only occurs after authentication request, but the authorization (and refused) to select only specific pages or Razor controller and operator in MVC.

It will take place after authorization (and refused) to select only specific pages or Razor and Action Controller in MVC.

The following example demonstrates the middleware sequence, wherein the static file request before the response is processed by the static compression middleware intermediate file. Static files are not compressed in the order of middleware. MVC from UseMvcWithDefaultRoute response may be compressed.

public void Configure(IApplicationBuilder app)
{
    app.UseStaticFiles();         // Static files not compressed
    app.UseResponseCompression();
    app.UseMvcWithDefaultRoute();
}

Use, Run, 和 Map

You may be used Use, Runand the Mapconfiguration HTTP pipeline. UseThe method of the duct may be short-circuited (i.e., a request may not delegate the call). RunIt is a convention, and some middleware component may be exposed at the end of the pipe run Run [the Middleware] Method. Map*Conventions used to extend branch ducts. The map matching a given request path to a branch request pipeline, if the request to start the path given path, the branch is executed.

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 use of the previous code  http: // localhost: 19219  request and response:

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 using the Map, the matching segment from the path HttpRequest.Pathis deleted, and appended to each request Http Request.PathBase.

MapWhenThe results given predicate request pipeline branch. Any type Func<HttpContext,bool>of verbs can be used to map the request to the new branch conduit. In the following example, the predicate for detecting the presence of branched query string variables:

 

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 the use of the above code  http: // localhost: 19219  request and response:

request response
localhost:1234 Hello from non-Map delegate.
localhost:1234/?branch=1 Branch used = master

MapSupports nested, for example:

app.Map("/level1", level1App => {
       level1App.Map("/level2a", level2AApp => {
           // "/level1/level2a"
           //...
       });
       level1App.Map("/level2b", level2BApp => {
           // "/level1/level2b"
           //...
       });
   });

MapA match may be a plurality of segments, for example:

app.Map("/level1/level2", HandleMultiSeg);

Built-in middleware

ASP.NET Core comes with the following middleware components:

 

Middleware description
Authentication It provides authentication support
HEARTS Configuring Cross-Origin Resource Sharing
Response Caching Provide support for cached responses
Response Compression Provide compression support response
Routing Request routing definitions and constraints
Session Provide user session management
Static Files Provide support for static file serving and directory browsing
URL Rewriting Middleware For rewriting Url, and redirection request support

 

Write middleware

Middleware typically packaged in a class, and the method using the extended exposure. Review the following middleware, it sets Culture current request from the query string:

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 test by passing Culture middleware, such as  http: // localhost: 19219 / culture = zh-CN?

The following code is moved to a middleware delegate 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 intermediate is exposed by extending the method IApplicationBuilder

using Microsoft.AspNetCore.Builder;

namespace Culture
{
    public static class RequestCultureMiddlewareExtensions
    {
        public static IApplicationBuilder UseRequestCulture(
            this IApplicationBuilder builder)
        {
            return builder.UseMiddleware<RequestCultureMiddleware>();
        }
    }
}

The following code from the Configurecall 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 explicit dependence, by its constructor expose dependencies. Middleware built once in the application life cycle. If you need to share services and middleware in the request, please refer to the following requests relevance.

Middleware component dependency may be resolved by the constructor dependency injection method parameters. UseMiddleware can also directly accept other parameters.

Each request dependencies

Because middleware is built upon application startup, instead of each request, so during each request, the scope of lifecycle services middleware constructor injection is not shared with other types of dependence. If you must share a scope service between middleware and other types, please add these services to the signature Invoke method. Invoke method may accept other injection parameters by the dependency filled. E.g:

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);
    }
}

 

Guess you like

Origin www.cnblogs.com/liuxiaoji/p/11490268.html