ASP.NET Core中间件初始化的实现

前言 

在日常使用ASP.NET Core开发的过程中我们多多少少会设计到使用中间件的场景,ASP.NET Core默认也为我们内置了许多的中间件,甚至有时候我们需要自定义中间件来帮我们处理一些请求管道过程中的处理。接下来,我们将围绕着以下几个问题来简单探究一下,关于ASP.NET Core中间件是如何初始化的

首先,使用UseMiddleware注册自定义中间件和直接Use的方式有何不同

其次,使用基于约定的方式定义中间件和使用实现IMiddleware接口的方式定义中间件有何不同

再次,使用基于约定的方式自定义中间件的究竟是如何约束我们编写的类和方法格式的

最后,使用约定的方式定义中间件,通过构造注入和通过Invoke方法注入的方式有何不同

接下来我们将围绕这几个核心点来逐步探究关于ASP.NET Core关于中间件初始化的神秘面纱,来指导我们以后使用它的时候需要有注意点,来减少踩坑的次数。

自定义的方式

使用自定义中间件的方式有好几种,咱们简单来演示一下三种比较常用方式。

Use方式

首先,也是最直接最简单的使用Use的方式,比如

app.Use(async (context, next) => { var endpoint = context.Features.Get<IEndpointFeature>()?.Endpoint; if (endpoint != null) { ResponseCacheAttribute responseCache = endpoint.Metadata.GetMetadata<ResponseCacheAttribute>(); if (responseCache != null) { //做一些事情 } } await next(); });

基于约定的方式

然后使用UseMiddleware也是我们比较常用的一种方式,这种方式使用起来相对于第一种来说,虽然使用起来可能会稍微繁琐一点,毕竟需要定义一个类,但是更好的符合符合面向对象的封装思想,它的使用方式大致如下,首先定义一个Middleware的类

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

编写完成之后,需要手动的将类注册到管道中才能生效,注册方式如下所示

app.UseMiddleware<RequestCultureMiddleware>();

实现IMiddleware的方式

还有一种方式是实现IMiddleware接口的方式,这种方式比如前两种方式常用,但是也确确实实的存在于ASP.NET Core中,既然存在也就有它存在的理由,我们也可以探究一下,它的使用方式也是需要自定义一个类去实现IMiddleware接口,如下所示

public class RequestCultureOtherMiddleware:IMiddleware { public async Task InvokeAsync(HttpContext context, RequestDelegate next) { var cultureQuery = context.Request.Query["culture"]; if (!string.IsNullOrWhiteSpace(cultureQuery)) { var culture = new CultureInfo(cultureQuery); CultureInfo.CurrentCulture = culture; CultureInfo.CurrentUICulture = culture; } await next(context); } }

这种方式和第二种方式略有不同,需要手动将中间件注册到容器中,至于声明周期也没做特殊要求,可以直接注册为单例模式

services.AddSingleton<IMiddleware,RequestCultureOtherMiddleware>();

完成上步操作之后,同样也需要将其注册到管道中去

app.UseMiddleware<RequestCultureOtherMiddleware>();

这种方式相对于第二种方式的主要区别在于灵活性方面的差异,它实现了IMiddleware接口,那就要受到IMiddleware接口的约束,也就是我们常说的里氏代换原则,首先我们可以先来看下IMiddleware接口的定义[点击查看源码👈]

public interface IMiddleware { /// <summary> /// 请求处理方法 /// </summary> /// <param>当前请求上下文</param> /// <param>请求管道中下一个中间件的委托</param> Task InvokeAsync (HttpContext context, RequestDelegate next); }

通过这个接口也就看出来InvokeAsync只能接受HttpContext和RequestDelegate参数,无法定义其他形式的参数,也没办法通过注入的方式编写InvokeAsync方法参数,说白了就是没有第二种方式灵活,受限较大。
关于常用的自定义中间件的方式,我们就先说到这里,我们也知道了如何定义使用中间件。接下来我们就来探讨一下,这么多种方式之间到底存在怎样的联系。

源码探究

上面我们已经演示了关于使用中间件的几种方式,那么这么几种使用方式之间有啥联系或区别,我们只看到了表面的,接下来我们来看一下关于中间件初始化的源码来一探究竟。
首先,无论那种形式都是基于IApplicationBuilder这个接口扩展而来的,所以我们先从这里下手,找到源码IApplicationBuilder位置[]可以看到以下代码

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyfdwd.html