• .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);
    }
  • 相关阅读:
    数据挖掘相关资料收集(持续更新)
    常见面试之机器学习算法思想简单梳理
    在c中保存状态
    lua 和 c
    lua 基础库
    lua 面向对象
    lua 高级
    lua 基础
    lua中的协程
    cocos2d中的可见性检测
  • 原文地址:https://www.cnblogs.com/topguntopgun/p/16344065.html
Copyright © 2020-2023  润新知