ASP.NET Core 自定义中间件

ASP.NET Core 自定义中间件

先来一个官方文档:https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/middleware/write?view=aspnetcore-3.1

中间件的组成

根据官方文档的说明,中间件必须包含以下内容:

  • 具有类型为 RequestDelegate 的参数的公共构造函数。
  • 名为 Invoke 或 InvokeAsync 的公共方法。 此方法必须:
    • 返回 Task。
    • 接受类型 HttpContext 的第一个参数。

Invoke/InvokeAsync可以有多个参数,都是依赖注入

由于中间件是在应用启动时构造的,而不是按请求构造的,因此在每个请求过程中,中间件构造函数使用的范围内生存期服务不与其他依赖关系注入类型共享。

根据官方的文档,最基本的中间件代码就长这样

public class CustomMiddleware
{
    private readonly RequestDelegate _next;

    public CustomMiddleware(RequestDelegate next)
    {
        this._next = next;
    }

    public async Task Invoke(HttpContext httpContext)
    {
        await this._next(httpContext);
    }
}

确实看的有点懵逼,于是我就去 GitHub 翻源码了

https://github.com/dotnet/aspnetcore

RequestDelegate 是个啥?

  • RequestDelegate:就是一个委托,用于处理请求的
    完整的是
/// <summary>
/// A function that can process an HTTP request.
/// </summary>
/// <param name="context">The <see cref="HttpContext"/> for the request.</param>
/// <returns>A task that represents the completion of request processing.</returns>
public delegate Task RequestDelegate(HttpContext context);

机翻一下

  1. 功能:可以处理HTTP请求的函数
  2. 参数:请求的HttpContext
  3. 返回值:表示请求处理完成的任务

那么这个 next 又是个啥?

我去翻了翻 AuthenticationMiddleware 的源码

/// <summary>
/// Initializes a new instance of <see cref="AuthenticationMiddleware"/>.
/// </summary>
/// <param name="next">The next item in the middleware pipeline.</param>
/// <param name="schemes">The <see cref="IAuthenticationSchemeProvider"/>.</param>
public AuthenticationMiddleware(RequestDelegate next, IAuthenticationSchemeProvider schemes)
{
    if (next == null)
    {
        throw new ArgumentNullException(nameof(next));
    }
    if (schemes == null)
    {
        throw new ArgumentNullException(nameof(schemes));
    }

    _next = next;
    Schemes = schemes;
}

还是机翻一下这个注解,next意思是中间件管道中的下一项

那么这时候应该就可以猜到 Invoke() 函数是做什么的了

没错,就是调用执行当前中间件

还是再翻一下 AuthenticationMiddleware 的源码

/// <summary>
/// Invokes the middleware performing authentication.
/// </summary>
/// <param name="context">The <see cref="HttpContext"/>.</param>
public async Task Invoke(HttpContext context)
{
    context.Features.Set<IAuthenticationFeature>(new AuthenticationFeature
    {
        OriginalPath = context.Request.Path,
        OriginalPathBase = context.Request.PathBase
    });

    // Give any IAuthenticationRequestHandler schemes a chance to handle the request
    var handlers = context.RequestServices.GetRequiredService<IAuthenticationHandlerProvider>();
    foreach (var scheme in await Schemes.GetRequestHandlerSchemesAsync())
    {
        var handler = await handlers.GetHandlerAsync(context, scheme.Name) as IAuthenticationRequestHandler;
        if (handler != null && await handler.HandleRequestAsync())
        {
            return;
        }
    }

    var defaultAuthenticate = await Schemes.GetDefaultAuthenticateSchemeAsync();
    if (defaultAuthenticate != null)
    {
        var result = await context.AuthenticateAsync(defaultAuthenticate.Name);
        if (result?.Principal != null)
        {
            context.User = result.Principal;
        }
    }

    await _next(context);
}

机翻一下这个函数的注解,功能是调用执行身份验证的中间件
什么嘛,我猜的还蛮准的嘛

中间件的使用

由于只是测试,所以我们的中间件就在控制台输出一个 Hello World 好了

public class CustomMiddleware
{
    private readonly RequestDelegate _next;

    public CustomMiddleware(RequestDelegate next)
    {
        this._next = next;
    }

    public async Task Invoke(HttpContext httpContext)
    {
        #region Request

        Console.WriteLine("Hello World");

        #endregion        

        await this._next(httpContext);

        #region Response

        #endregion        
    }
}

然后再写一个扩展方法

public static class CustomMiddlewareExtensions
{
    public static IApplicationBuilder UseCustom(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<CustomMiddleware>();
    }
}

然后就可以在 Startup 中使用了

app.UseCustom();

完整的 Startup ,我只加了上面那句

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseRouting();

        app.UseCustom();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapGet("/", async context =>
            {
                await context.Response.WriteAsync("Hello World!");
            });
        });
    }
}

启动,访问一个页面,效果图

输出了预期结果

ASP.NET Core 自定义中间件 结束

项目结构

posted @ 2021-07-20 16:05  .NET好耶  阅读(160)  评论(0编辑  收藏  举报