ASP.NET Core Middleware 学习

本文介绍了ASP.NET Core中间件,它是装配到应用管道处理请求和响应的软件。阐述了使用其创建中间件管道的方式,包括请求委托的调用及短路情况。还说明了中间件顺序的常见应用方案,介绍了Use、Run和Map的用法,提及内置中间件,讲解了编写中间件的内嵌和类方式,以及按请求依赖项的注意点。

1.介绍

中间件是一种装配到应用管道以处理请求和响应的软件。 每个组件:

  • 选择是否将请求传递到管道中的下一个组件。
  • 可在调用管道中的下一个组件前后执行工作。

2.使用 IApplicationBuilder 创建中间件管道

ASP.NET Core 请求管道包含一系列请求委托,依次调用。每个委托均可在下一个委托前后执行操作,委托还可以决定不将请求传递给下一个委托,这就是对请求管道进行短路。

ASP.NET Core 请求管道

public class Startup
{
    public void Configure(IApplicationBuilder app)
    {
        app.Use(async (context, next) =>
        {
            // Do work that doesn't write to the Response.
            await next.Invoke();
            // Do logging or other work that doesn't write to the Response.
        });

        app.Run(async context =>
        {
            await context.Response.WriteAsync("Hello from 2nd delegate.");
        });
    }
}

警告:在向客户端发送响应后,请勿调用 next.Invoke

3.中间件顺序(常见应用方案)

  1. 异常/错误处理
  2. HTTP 严格传输安全协议
  3. HTTPS 重定向
  4. 静态文件服务器
  5. Cookie 策略实施
  6. 身份验证
  7. 会话
  8. MVC

4.Use、Run 和 Map

  • Use 方法可使管道短路(即不调用 next 请求委托);
  • Run 是一种约定,某些中间件组件公开在管道末尾运行的 Run[Middleware] 方法;
  • Map 扩展用作约定来创建管道分支,Map* 基于给定请求路径的匹配项来创建请求管道分支。如果请求路径以给定路径开头,则执行分支;
    • 使用 Map 时,将从 HttpRequest.Path 中删除匹配的路径段,并针对每个请求将该路径段追加到 HttpRequest.PathBase
    • MapWhen(IApplicationBuilder, Func<HttpContext,Boolean>, Action<IApplicationBuilder>) 基于给定谓词的结果创建请求管道分支;
    • Map 支持嵌套;
    • Map 可同时匹配多个段;

5.内置中间件

中间件描述顺序
身份验证提供身份验证支持。在需要 HttpContext.User 之前。OAuth 回叫的终端。
Cookie 策略跟踪用户是否同意存储个人信息,并强制实施 cookie 字段(如 secure 和 SameSite)的最低标准。在发出 cookie 的中间件之前。 示例:身份验证、会话、MVC (TempData)。
CORS配置跨域资源共享。在使用 CORS 的组件之前。
诊断配置诊断。在生成错误的组件之前。
转接头将代理标头转发到当前请求。在使用已更新字段的组件之前。 示例:方案、主机、客户端 IP、方法。
HTTP 方法重写允许传入 POST 请求重写方法。在使用已更新方法的组件之前。
HTTPS 重定向将所有 HTTP 请求重定向到 HTTPS(ASP.NET Core 2.1 或更高版本)。在使用 URL 的组件之前。
HTTP 严格传输安全性 (HSTS)添加特殊响应标头的安全增强中间件(ASP.NET Core 2.1 或更高版本)。在发送响应之前,修改请求的组件之后。 示例:转接头、URL 重写。
MVC用 MVC/Razor Pages 处理请求(ASP.NET Core 2.0 或更高版本)。如果请求与路由匹配,则为终端。
OWIN与基于 OWIN 的应用、服务器和中间件进行互操作。如果 OWIN 中间件处理完请求,则为终端。
响应缓存提供对缓存响应的支持。在需要缓存的组件之前。
响应压缩提供对压缩响应的支持。在需要压缩的组件之前。
请求本地化提供本地化支持。在对本地化敏感的组件之前。
路由定义和约束请求路由。用于匹配路由的终端。
会话提供对管理用户会话的支持。在需要会话的组件之前。
静态文件为提供静态文件和目录浏览提供支持。如果请求与文件匹配,则为终端。
URL 重写提供对重写 URL 和重定向请求的支持。在使用 URL 的组件之前。
WebSockets启用 WebSockets 协议。在接受 WebSocket 请求所需的组件之前。

6.编写中间件

6.1 内嵌

app.Use((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
    return next();
});

6.2 类(推荐)

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

中间件应通过在其构造函数中公开其依赖项来遵循显式依赖项原则

7.按请求依赖项

由于中间件是在应用启动时构造的,而不是按请求构造的,故需要注意生命周期。可考虑将依赖服务添加到 Invoke 方法签名。

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

参考文章

1 中间件
2 基于工厂的中间件
3 第三方容器的中间件

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值