Pisanie niestandardowego oprogramowania pośredniczącego platformy ASP.NET Core

Przez Fiyaz Hasan, Rick Anderson i Steve Smith

Oprogramowanie pośredniczące to oprogramowanie, które jest wmontowane w potok aplikacji w celu obsługi żądań i odpowiedzi. ASP.NET Core udostępnia bogaty zestaw wbudowanych składników oprogramowania pośredniczącego, ale w niektórych scenariuszach warto napisać niestandardowe oprogramowanie pośredniczące.

W tym temacie opisano sposób pisania oprogramowania pośredniczącego opartego na konwencji. Aby uzyskać podejście korzystające z silnego pisania i aktywacji na żądanie, zobacz Aktywacja oprogramowania pośredniczącego opartego na fabryce w ASP.NET Core.

Klasa oprogramowania pośredniczącego

Oprogramowanie pośredniczące jest zwykle hermetyzowane w klasie i udostępniane za pomocą metody rozszerzenia. Rozważ następujące wbudowane oprogramowanie pośredniczące, które ustawia kulturę bieżącego żądania z ciągu zapytania:

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

Powyższe wyróżnione wbudowane oprogramowanie pośredniczące służy do demonstrowania tworzenia składnika oprogramowania pośredniczącego przez wywołanie metody Microsoft.AspNetCore.Builder.UseExtensions.Use. Use Poprzednia metoda rozszerzenia dodaje delegata oprogramowania pośredniczącego zdefiniowanego w wierszu do potoku żądania aplikacji.

Istnieją dwa przeciążenia dostępne dla Use rozszerzenia:

  • Jeden przyjmuje element HttpContext i Func<Task>. Wywołaj parametr Func<Task> bez żadnych parametrów.
  • Drugi przyjmuje element HttpContext i RequestDelegate. Wywołaj element RequestDelegate , przekazując element HttpContext.

Preferuj użycie późniejszego przeciążenia, ponieważ zapisuje dwa wewnętrzne alokacje dla poszczególnych żądań, które są wymagane podczas korzystania z innego przeciążenia.

Przetestuj oprogramowanie pośredniczące, przekazując kulturę. Na przykład zażądaj .https://localhost:5001/?culture=es-es

Aby uzyskać wbudowaną obsługę lokalizacji ASP.NET Core, zobacz Globalizacja i lokalizacja w programie ASP.NET Core.

Poniższy kod przenosi delegata oprogramowania pośredniczącego do klasy:

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

Klasa oprogramowania pośredniczącego musi zawierać następujące elementy:

  • Publiczny konstruktor z parametrem typu RequestDelegate.
  • Publiczna metoda o nazwie Invoke lub InvokeAsync. Ta metoda musi:
    • Zwróć wartość Task.
    • Zaakceptuj pierwszy parametr typu HttpContext.

Dodatkowe parametry konstruktora i Invoke/InvokeAsync są wypełniane przez wstrzykiwanie zależności (DI).

Zazwyczaj metoda rozszerzenia jest tworzona w celu uwidocznienia oprogramowania pośredniczącego za pomocą polecenia 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>();
    }
}

Poniższy kod wywołuje oprogramowanie pośredniczące z programu 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();

Zależności oprogramowania pośredniczącego

Oprogramowanie pośredniczące powinno postępować zgodnie z regułą jawnych zależności, uwidaczniając jej zależności w konstruktorze. Oprogramowanie pośredniczące jest tworzone raz na okres istnienia aplikacji.

Składniki oprogramowania pośredniczącego mogą rozwiązywać swoje zależności od wstrzykiwania zależności (DI) za pomocą parametrów konstruktora. UseMiddleware może również bezpośrednio akceptować dodatkowe parametry.

Zależności oprogramowania pośredniczącego dla poszczególnych żądań

Oprogramowanie pośredniczące jest tworzone podczas uruchamiania aplikacji i dlatego ma czas życia aplikacji. Usługi okresu istnienia o określonym zakresie używane przez konstruktory oprogramowania pośredniczącego nie są współużytkowane z innymi typami wstrzykiwanymi zależnościami podczas każdego żądania. Aby udostępnić usługę o określonym zakresie między oprogramowaniem pośredniczącym a innymi typami, dodaj te usługi do InvokeAsync podpisu metody. Metoda InvokeAsync może akceptować dodatkowe parametry wypełnione przez 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>();
    }
}

Opcje okresu istnienia i rejestracji zawierają kompletny przykład oprogramowania pośredniczącego z usługami o określonym zakresie.

Poniższy kod służy do testowania poprzedniego oprogramowania pośredniczącego:

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

Interfejs i implementacja IMessageWriter :

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

Dodatkowe zasoby

Autorzy: Rick Anderson i Steve Smith

Oprogramowanie pośredniczące to oprogramowanie, które jest wmontowane w potok aplikacji w celu obsługi żądań i odpowiedzi. ASP.NET Core udostępnia bogaty zestaw wbudowanych składników oprogramowania pośredniczącego, ale w niektórych scenariuszach warto napisać niestandardowe oprogramowanie pośredniczące.

Uwaga

W tym temacie opisano sposób pisania oprogramowania pośredniczącego opartego na konwencji. Aby uzyskać podejście korzystające z silnego pisania i aktywacji na żądanie, zobacz Aktywacja oprogramowania pośredniczącego opartego na fabryce w ASP.NET Core.

Klasa oprogramowania pośredniczącego

Oprogramowanie pośredniczące jest zwykle hermetyzowane w klasie i udostępniane za pomocą metody rozszerzenia. Rozważ następujące oprogramowanie pośredniczące, które ustawia kulturę dla bieżącego żądania z ciągu zapytania:

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

    }
}

Powyższy przykładowy kod służy do demonstrowania tworzenia składnika oprogramowania pośredniczącego. Aby uzyskać wbudowaną obsługę lokalizacji ASP.NET Core, zobacz Globalizacja i lokalizacja w programie ASP.NET Core.

Przetestuj oprogramowanie pośredniczące, przekazując kulturę. Na przykład zażądaj .https://localhost:5001/?culture=no

Poniższy kod przenosi delegata oprogramowania pośredniczącego do klasy:

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

Klasa oprogramowania pośredniczącego musi zawierać następujące elementy:

  • Publiczny konstruktor z parametrem typu RequestDelegate.
  • Publiczna metoda o nazwie Invoke lub InvokeAsync. Ta metoda musi:
    • Zwróć wartość Task.
    • Zaakceptuj pierwszy parametr typu HttpContext.

Dodatkowe parametry konstruktora i Invoke/InvokeAsync są wypełniane przez wstrzykiwanie zależności (DI).

Zależności oprogramowania pośredniczącego

Oprogramowanie pośredniczące powinno postępować zgodnie z regułą jawnych zależności, uwidaczniając jej zależności w konstruktorze. Oprogramowanie pośredniczące jest tworzone raz na okres istnienia aplikacji. Jeśli chcesz udostępnić usługi za pomocą oprogramowania pośredniczącego, zobacz sekcję Zależności oprogramowania pośredniczącego dla poszczególnych żądań.

Składniki oprogramowania pośredniczącego mogą rozwiązywać swoje zależności od wstrzykiwania zależności (DI) za pomocą parametrów konstruktora. UseMiddleware może również bezpośrednio akceptować dodatkowe parametry.

Zależności oprogramowania pośredniczącego dla poszczególnych żądań

Ponieważ oprogramowanie pośredniczące jest tworzone podczas uruchamiania aplikacji, a nie na żądanie, zakres usług okresowych używanych przez konstruktory oprogramowania pośredniczącego nie jest współużytkowany z innymi typami wstrzykiwanymi zależnościami podczas każdego żądania. Jeśli musisz udostępnić usługę o określonym zakresie między oprogramowaniem pośredniczącym a innymi typami, dodaj te usługi do InvokeAsync podpisu metody. Metoda InvokeAsync może akceptować dodatkowe parametry wypełnione przez 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);
    }
}

Opcje okresu istnienia i rejestracji zawierają kompletny przykład oprogramowania pośredniczącego z usługami o określonym zakresie.

Metoda rozszerzenia oprogramowania pośredniczącego

Następująca metoda rozszerzenia uwidacznia oprogramowanie pośredniczące za pomocą polecenia IApplicationBuilder:

using Microsoft.AspNetCore.Builder;

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

Poniższy kod wywołuje oprogramowanie pośredniczące z programu Startup.Configure:

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

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

Dodatkowe zasoby