Psaní vlastního middlewaru ASP.NET Core

Fiyaz Hasan, Rick Anderson a Steve Smith

Middleware je software sestavený do kanálu aplikace pro zpracování požadavků a odpovědí. ASP.NET Core poskytuje bohatou sadu integrovaných komponent middlewaru, ale v některých scénářích můžete chtít napsat vlastní middleware.

Toto téma popisuje, jak psát middleware založený na konvencích. Přístup, který používá silné psaní a aktivaci na vyžádání, najdete v tématu Aktivace middlewaru založeného na továrně v ASP.NET Core.

Middleware – třída

Middleware je obecně zapouzdřen ve třídě a vystaven pomocí rozšiřující metody. Zvažte následující vložený middleware, který nastaví jazykovou verzi aktuálního požadavku z řetězce dotazu:

using System.Globalization;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.UseHttpsRedirection();

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

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

app.Run();

Předchozí zvýrazněný vložený middleware se používá k předvedení vytvoření middlewarové komponenty voláním Microsoft.AspNetCore.Builder.UseExtensions.Use. Předchozí Use metoda rozšíření přidá do kanálu požadavku aplikace delegovaný middleware definovaný v řádku.

Pro rozšíření jsou k dispozici Use dvě přetížení:

  • Jeden vezme HttpContext a Func<Task>. Func<Task> Vyvolání bez jakýchkoli parametrů
  • Druhý si vezme HttpContext a RequestDelegate. RequestDelegate Vyvoláním voláním metody HttpContext.

Preferujte použití pozdějšího přetížení, protože ukládá dvě interní přidělení požadavků, které jsou vyžadovány při použití jiného přetížení.

Otestujte middleware předáním jazykové verze. Například požadavek https://localhost:5001/?culture=es-es.

Informace o integrované podpoře lokalizací ASP.NET Core najdete v tématu Globalizace a lokalizace v ASP.NET Core.

Následující kód přesune delegáta middlewaru do třídy:

using System.Globalization;

namespace Middleware.Example;

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

Middleware třída musí obsahovat:

  • Veřejný konstruktor s parametrem typu RequestDelegate.
  • Veřejná metoda s názvem Invoke nebo InvokeAsync. Tato metoda musí:
    • Vrácení znaku Task.
    • Přijmout první parametr typu HttpContext.

Další parametry konstruktoru a Invoke/InvokeAsync jsou naplněny injektáží závislostí (DI).

Obvykle se vytvoří rozšiřující metoda pro zveřejnění middlewaru prostřednictvím IApplicationBuilder:

using System.Globalization;

namespace Middleware.Example;

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

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

Následující kód volá middleware z Program.cs:

using Middleware.Example;
using System.Globalization;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.UseHttpsRedirection();

app.UseRequestCulture();

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

app.Run();

Závislosti middlewaru

Middleware by měl postupovat podle explicitního principu závislostí tím, že v jeho konstruktoru zpřístupňuje jeho závislosti. Middleware se konstruuje jednou za dobu životnosti aplikace.

Komponenty middlewaru mohou vyřešit své závislosti z injektáže závislostí (DI) prostřednictvím parametrů konstruktoru. UseMiddleware může také přijímat další parametry přímo.

Závislosti middlewaru pro jednotlivé požadavky

Middleware se konstruuje při spuštění aplikace, a proto má životnost aplikace. Služby s vymezenou životností používané konstruktory middlewaru se během každého požadavku nesdílí s jinými typy vloženými do závislostí. Pokud chcete sdílet vymezenou službu mezi middlewarem a jinými typy, přidejte tyto služby do InvokeAsync podpisu metody. Metoda InvokeAsync může přijmout další parametry, které jsou naplněny DI:

namespace Middleware.Example;

public class MyCustomMiddleware
{
    private readonly RequestDelegate _next;

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

    // IMessageWriter is injected into InvokeAsync
    public async Task InvokeAsync(HttpContext httpContext, IMessageWriter svc)
    {
        svc.Write(DateTime.Now.Ticks.ToString());
        await _next(httpContext);
    }
}

public static class MyCustomMiddlewareExtensions
{
    public static IApplicationBuilder UseMyCustomMiddleware(
        this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<MyCustomMiddleware>();
    }
}

Možnosti životnosti a registrace obsahují kompletní ukázku middlewaru s vymezenými službami životnosti.

Následující kód slouží k otestování předchozího middlewaru:

using Middleware.Example;
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddScoped<IMessageWriter, LoggingMessageWriter>();

var app = builder.Build();

app.UseHttpsRedirection();

app.UseMyCustomMiddleware();

app.MapGet("/", () => "Hello World!");

app.Run();

Rozhraní IMessageWriter a implementace:

namespace Middleware.Example;

public interface IMessageWriter
{
    void Write(string message);
}

public class LoggingMessageWriter : IMessageWriter
{

    private readonly ILogger<LoggingMessageWriter> _logger;

    public LoggingMessageWriter(ILogger<LoggingMessageWriter> logger) =>
        _logger = logger;

    public void Write(string message) =>
        _logger.LogInformation(message);
}

Další prostředky

Autor: Rick Anderson a Steve Smith

Middleware je software sestavený do kanálu aplikace pro zpracování požadavků a odpovědí. ASP.NET Core poskytuje bohatou sadu integrovaných komponent middlewaru, ale v některých scénářích můžete chtít napsat vlastní middleware.

Poznámka

Toto téma popisuje, jak psát middleware založený na konvencích. Přístup, který používá silné psaní a aktivaci na vyžádání, najdete v tématu Aktivace middlewaru založeného na továrně v ASP.NET Core.

Middleware – třída

Middleware je obecně zapouzdřen ve třídě a vystaven pomocí rozšiřující metody. Představte si následující middleware, který nastaví jazykovou verzi aktuálního požadavku z řetězce dotazu:

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

    }
}

Předchozí vzorový kód slouží k předvedení vytvoření komponenty middlewaru. Informace o integrované podpoře lokalizací ASP.NET Core najdete v tématu Globalizace a lokalizace v ASP.NET Core.

Otestujte middleware předáním jazykové verze. Například požadavek https://localhost:5001/?culture=no.

Následující kód přesune delegáta middlewaru do třídy:

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

Middleware třída musí obsahovat:

  • Veřejný konstruktor s parametrem typu RequestDelegate.
  • Veřejná metoda s názvem Invoke nebo InvokeAsync. Tato metoda musí:
    • Vrácení znaku Task.
    • Přijmout první parametr typu HttpContext.

Další parametry konstruktoru a Invoke/InvokeAsync jsou naplněny injektáží závislostí (DI).

Závislosti middlewaru

Middleware by měl postupovat podle explicitního principu závislostí tím, že v jeho konstruktoru zpřístupňuje jeho závislosti. Middleware se konstruuje jednou za dobu životnosti aplikace. Pokud potřebujete sdílet služby s middlewarem v rámci požadavku, přečtěte si část Závislostí middlewaru podle požadavku.

Komponenty middlewaru mohou vyřešit své závislosti z injektáže závislostí (DI) prostřednictvím parametrů konstruktoru. UseMiddleware může také přijímat další parametry přímo.

Závislosti middlewaru pro jednotlivé požadavky

Vzhledem k tomu, že middleware se vytváří při spuštění aplikace, nikoli při každém požadavku, nejsou během každého požadavku sdíleny s jinými typy vloženými do závislostí. Pokud musíte sdílet vymezenou službu mezi middlewarem a dalšími typy, přidejte tyto služby do InvokeAsync podpisu metody. Metoda InvokeAsync může přijmout další parametry, které jsou naplněny DI:

public class CustomMiddleware
{
    private readonly RequestDelegate _next;

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

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

Možnosti životnosti a registrace obsahují kompletní ukázku middlewaru s vymezenými službami životnosti.

Metoda rozšíření middlewaru

Následující metoda rozšíření zpřístupňuje middleware prostřednictvím IApplicationBuilder:

using Microsoft.AspNetCore.Builder;

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

Následující kód volá middleware z Startup.Configure:

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

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

Další prostředky