사용자 지정 ASP.NET Core 미들웨어 작성

작성자: Fiyaz Hasan, Rick AndersonSteve Smith

미들웨어는 요청 및 응답을 처리하는 앱 파이프라인으로 어셈블리되는 소프트웨어입니다. ASP.NET Core는 풍부한 기본 제공 미들웨어 구성 요소 세트를 제공하지만 일부 시나리오에서는 사용자 지정 미들웨어를 작성하려고 할 수 있습니다.

이 항목에서는 규칙 기반 미들웨어를 작성하는 방법을 설명합니다. 강력한 형식화 및 요청당 활성화를 사용하는 접근 방법에 대해서는 ASP.NET Core의 팩터리 기반 미들웨어 활성화를 참조하세요.

미들웨어 클래스

미들웨어는 일반적으로 클래스에서 캡슐화되고 확장 메서드로 노출됩니다. 쿼리 문자열에서 현재 요청에 대한 문화권을 설정하는 다음 인라인 미들웨어를 참조하세요.

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

앞서 강조 표시된 인라인 미들웨어는 Microsoft.AspNetCore.Builder.UseExtensions.Use를 호출하여 미들웨어 구성 요소를 만드는 방법을 보여 주는 데 사용됩니다. 위의 Use 확장 메서드는 애플리케이션의 요청 파이프라인에 인라인으로 정의된 미들웨어 대리자를 추가합니다.

Use 확장에 사용할 수 있는 두 가지 오버로드가 있습니다.

  • 하나는 HttpContextFunc<Task>를 사용합니다. 아무 매개 변수 없이 Func<Task>를 호출합니다.
  • 다른 하나는 HttpContextRequestDelegate를 사용합니다. HttpContext를 전달하여 RequestDelegate를 호출합니다.

다른 오버로드를 사용할 때 필요한 두 개의 내부 요청별 할당이 필요하지 않으므로 이 오버로드를 사용하는 것이 좋습니다.

문화권을 전달하여 미들웨어를 테스트합니다. 예를 들어 https://localhost:5001/?culture=es-es를 요청합니다.

ASP.NET Core의 기본 제공 지역화 지원은 ASP.NET Core에서 세계화 및 지역화를 참조하세요.

다음 코드는 미들웨어 대리자를 클래스로 이동합니다.

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

미들웨어 클래스는 다음을 포함해야 합니다.

  • RequestDelegate 형식의 매개 변수가 있는 공용 생성자
  • Invoke 또는 InvokeAsync라는 공용 메서드. 이 메서드는 다음을 수행해야 합니다.
    • Task를 반환합니다.
    • HttpContext 형식의 첫 번째 매개 변수를 허용합니다.

생성자 및 Invoke/InvokeAsync의 추가 매개 변수는 DI(종속성 주입)로 채워집니다.

일반적으로 확장 메서드는 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>();
    }
}

다음 코드는 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();

미들웨어 종속성

미들웨어는 해당 생성자에서 해당 종속성을 노출하여 명시적 종속성 원칙을 따라야 합니다. 미들웨어는 애플리케이션 수명당 한 번 생성됩니다.

미들웨어 구성 요소는 생성자 매개 변수를 통해 DI(종속성 주입)에서 해당 종속성을 확인할 수 있습니다. UseMiddleware는 추가 매개 변수를 직접 수락할 수도 있습니다.

요청당 미들웨어 종속성

미들웨어는 앱 시작 시에 생성되며 애플리케이션 수명이 있습니다. 미들웨어 생성자에 의해 사용되는 범위가 지정된 수명 서비스는 각 요청 중에 다른 종속성 주입된 형식과 공유되지 않습니다. 범위가 지정된 서비스를 미들웨어와 기타 유형 간에 공유해야 하는 경우 이러한 서비스를 InvokeAsync 메서드의 시그너처에 추가합니다. InvokeAsync 메서드는 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>();
    }
}

수명 및 등록 옵션에는 ‘범위가 지정된’ 수명 서비스를 사용하는 미들웨어의 전체 샘플이 포함되어 있습니다.

다음 코드는 위의 미들웨어를 테스트하는 데 사용됩니다.

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

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

추가 리소스

작성자: Rick AndersonSteve Smith

미들웨어는 요청 및 응답을 처리하는 앱 파이프라인으로 어셈블리되는 소프트웨어입니다. ASP.NET Core는 풍부한 기본 제공 미들웨어 구성 요소 세트를 제공하지만 일부 시나리오에서는 사용자 지정 미들웨어를 작성하려고 할 수 있습니다.

참고 항목

이 항목에서는 규칙 기반 미들웨어를 작성하는 방법을 설명합니다. 강력한 형식화 및 요청당 활성화를 사용하는 접근 방법에 대해서는 ASP.NET Core의 팩터리 기반 미들웨어 활성화를 참조하세요.

미들웨어 클래스

미들웨어는 일반적으로 클래스에서 캡슐화되고 확장 메서드로 노출됩니다. 쿼리 문자열에서 현재 요청에 대한 문화권을 설정하는 다음 미들웨어를 고려합니다.

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

    }
}

위의 샘플 코드는 미들웨어 구성 요소를 만드는 방법을 보여주는 데 사용됩니다. ASP.NET Core의 기본 제공 지역화 지원은 ASP.NET Core에서 세계화 및 지역화를 참조하세요.

문화권을 전달하여 미들웨어를 테스트합니다. 예를 들어 https://localhost:5001/?culture=no를 요청합니다.

다음 코드는 미들웨어 대리자를 클래스로 이동합니다.

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

미들웨어 클래스는 다음을 포함해야 합니다.

  • RequestDelegate 형식의 매개 변수가 있는 공용 생성자
  • Invoke 또는 InvokeAsync라는 공용 메서드. 이 메서드는 다음을 수행해야 합니다.
    • Task를 반환합니다.
    • HttpContext 형식의 첫 번째 매개 변수를 허용합니다.

생성자 및 Invoke/InvokeAsync의 추가 매개 변수는 DI(종속성 주입)로 채워집니다.

미들웨어 종속성

미들웨어는 해당 생성자에서 해당 종속성을 노출하여 명시적 종속성 원칙을 따라야 합니다. 미들웨어는 애플리케이션 수명당 한 번 생성됩니다. 요청 내에서 서비스를 미들웨어와 공유해야 하는 경우 요청당 미들웨어 종속성 섹션을 참조하세요.

미들웨어 구성 요소는 생성자 매개 변수를 통해 DI(종속성 주입)에서 해당 종속성을 확인할 수 있습니다. UseMiddleware는 추가 매개 변수를 직접 수락할 수도 있습니다.

요청당 미들웨어 종속성

미들웨어는 요청당이 아닌 앱 시작 시 생성되므로 미들웨어 생성자에 의해 사용되는 범위가 지정된 수명 서비스는 각 요청 중에 다른 종속성 주입된 형식과 공유되지 않습니다. 범위가 지정된 서비스를 미들웨어와 다른 형식 간에 공유해야 하는 경우 이러한 서비스를 InvokeAsync 메서드의 서명에 추가합니다. InvokeAsync 메서드는 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);
    }
}

수명 및 등록 옵션에는 ‘범위가 지정된’ 수명 서비스를 사용하는 미들웨어의 전체 샘플이 포함되어 있습니다.

미들웨어 확장 메서드

다음 확장 메서드는 IApplicationBuilder를 통해 미들웨어를 공개합니다.

using Microsoft.AspNetCore.Builder;

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

다음 코드는 Startup.Configure에서 미들웨어를 호출합니다.

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

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

추가 리소스