Escritura de middleware de ASP.NET Core personalizadoWrite custom ASP.NET Core middleware

Por Rick Anderson y Steve SmithBy Rick Anderson and Steve Smith

El software intermedio es un software que se ensambla en una canalización de una aplicación para controlar las solicitudes y las respuestas.Middleware is software that's assembled into an app pipeline to handle requests and responses. ASP.NET Core proporciona un completo conjunto de componentes de middleware integrados, pero en algunos escenarios es posible que quiera escribir middleware personalizado.ASP.NET Core provides a rich set of built-in middleware components, but in some scenarios you might want to write a custom middleware.

Clase de middlewareMiddleware class

El middleware normalmente está encapsulado en una clase y se expone con un método de extensión.Middleware is generally encapsulated in a class and exposed with an extension method. Use el siguiente software intermedio a modo de ejemplo. En este se establece la referencia cultural de la solicitud actual a partir de la cadena de solicitud:Consider the following middleware, which sets the culture for the current request from a query string:

public class Startup
{
    public void Configure(IApplicationBuilder app)
    {
        app.Use(async (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
            await next();
        });

        app.Run(async (context) =>
        {
            await context.Response.WriteAsync(
                $"Hello {CultureInfo.CurrentCulture.DisplayName}");
        });

    }
}

El código de ejemplo anterior se usa para mostrar la creación de un componente de software intermedio.The preceding sample code is used to demonstrate creating a middleware component. Para obtener más información sobre la compatibilidad con la localización integrada de ASP.NET Core, vea Globalización y localización en ASP.NET Core.For ASP.NET Core's built-in localization support, see Globalización y localización en ASP.NET Core.

Pruebe el middleware pasando la referencia cultural.Test the middleware by passing in the culture. Por ejemplo, solicite https://localhost:5001/?culture=no.For example, request https://localhost:5001/?culture=no.

El código siguiente mueve el delegado de middleware a una clase:The following code moves the middleware delegate 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 async Task InvokeAsync(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
            await _next(context);
        }
    }
}

La clase de middleware debe incluir:The middleware class must include:

  • Un constructor público con un parámetro de tipo RequestDelegate.A public constructor with a parameter of type RequestDelegate.
  • Un método público llamado Invoke o InvokeAsync.A public method named Invoke or InvokeAsync. Este método debe:This method must:
    • Devolver Task.Return a Task.
    • Aceptar un primer parámetro de tipo HttpContext.Accept a first parameter of type HttpContext.

Los parámetros adicionales para el constructor y Invoke/InvokeAsync se rellenan mediante la inserción de dependencias (DI).Additional parameters for the constructor and Invoke/InvokeAsync are populated by dependency injection (DI).

Dependencias de middlewareMiddleware dependencies

El middleware debería seguir el principio de dependencias explicitas mediante la exposición de sus dependencias en el constructor.Middleware should follow the Explicit Dependencies Principle by exposing its dependencies in its constructor. El middleware se construye una vez por duración de la aplicación.Middleware is constructed once per application lifetime. Si necesita compartir servicios con software intermedio en una solicitud, vea la sección Dependencias de middleware bajo solicitud.See the Per-request middleware dependencies section if you need to share services with middleware within a request.

Los componentes de software intermedio pueden resolver sus dependencias de una inserción de dependencias (DI) mediante parámetros del constructor.Middleware components can resolve their dependencies from dependency injection (DI) through constructor parameters. UseMiddleware<T> también puede aceptar parámetros adicionales directamente.UseMiddleware<T> can also accept additional parameters directly.

Dependencias de middleware bajo solicitudPer-request middleware dependencies

Dado que el software intermedio se construye al inicio de la aplicación y no bajo solicitud, los servicios de duración con ámbito que usan los constructores de software intermedio no se comparten con otros tipos insertados mediante dependencias durante cada solicitud.Because middleware is constructed at app startup, not per-request, scoped lifetime services used by middleware constructors aren't shared with other dependency-injected types during each request. Si debe compartir un servicio con ámbito entre su middleware y otros tipos, agregue esos servicios a la signatura del método Invoke.If you must share a scoped service between your middleware and other types, add these services to the Invoke method's signature. El método Invoke puede aceptar parámetros adicionales que la inserción de dependencias propaga:The Invoke method can accept additional parameters that are populated by DI:

public class CustomMiddleware
{
    private readonly RequestDelegate _next;

    public CustomMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    // IMyScopedService is injected into Invoke
    public async Task Invoke(HttpContext httpContext, IMyScopedService svc)
    {
        svc.MyProperty = 1000;
        await _next(httpContext);
    }
}

Método de extensión de middlewareMiddleware extension method

El método de extensión siguiente expone el software intermedio mediante IApplicationBuilder:The following extension method exposes the middleware through IApplicationBuilder:

using Microsoft.AspNetCore.Builder;

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

El código siguiente llama al middleware desde Startup.Configure:The following code calls the middleware from Startup.Configure:

public class Startup
{
    public void Configure(IApplicationBuilder app)
    {
        app.UseRequestCulture();

        app.Run(async (context) =>
        {
            await context.Response.WriteAsync(
                $"Hello {CultureInfo.CurrentCulture.DisplayName}");
        });
    }
}

Recursos adicionalesAdditional resources