.NET Core 之中间件学习

中间件是一种装配到应用管道以处理请求和响应的软件。 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 扩展可以使用两个重载:

  • 一个重载采用 HttpContext 和 Func<Task>。 不使用任何参数调用 Func<Task>
  • 一个重载采用 HttpContext 和 RequestDelegate。 通过传递 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>();
    }
}
复制代码

中间件依赖项

中间件应通过在其构造函数中公开其依赖项来遵循显式依赖项原则。 在每个应用程序生存期构造一次中间件。

中间件组件可通过构造函数参数从依赖关系注入 (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>();
    }
}
复制代码

 

生存期和注册选项包含范围内生存期服务的中间件的完整示例。

以下代码用于测试以上中间件:

C#
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 接口和实现:

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

posted on   topguntopgun  阅读(556)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
历史上的今天:
2019-06-05 android studio 黑屏问题
2019-06-05 java.lang.SecurityException: Permission denied (missing INTERNET permission?)
2019-06-05 未能加载文件或程序集“MySql.Data”或它的某一个依赖项。找到的程序集清单定义与程序集引用不匹配。 (异常来自 HRESULT:0x80131040)

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

统计

点击右上角即可分享
微信分享提示