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

上面的代码比较抽象,其实主要是因为它是基于表达式树进行各种操作的,如果对表达式树比较熟悉的话,可能对上面的代码理解起来还好一点,如果不熟悉表达式树的话,可能理解起来比较困难,不过还是建议简单学习一下Expression相关的操作,慢慢的发现还是挺有意思的,它的性能整体来说比传统的反射性能也会更好一点。其实Compile主要实现的操作转化为我们比较容易理解的代码的话就是下面所示的操作,如果我们编写了一个如下的中间件代码

public class Middleware { public Task Invoke(HttpContext context, ILoggerFactory loggerFactory) { } }

那么通过Compile方法将转换为类似以下形式的操作,这样说的话可能会好理解一点

Task Invoke(Middleware instance, HttpContext httpContext, IServiceProvider provider) { return instance.Invoke(httpContext, (ILoggerFactory)UseMiddlewareExtensions.GetService(provider, typeof(ILoggerFactory)); }

通过上面的源码分析我们了解到,基于约定的方式定义的中间件实例是通过ActivatorUtilities类创建的,而且创建实例是在返回RequestDelegate委托之前,IApplicationBuilder的Use方法只会在首次运行的时候执行,后续管道串联执行的其实正是它返回的结果RequestDelegate这个委托。但是执行转换Invoke或InvokeAsync方法为执行委托的操作却是在返回的RequestDelegate委托当中,也就是我们每次请求管道会处理的逻辑中。这个逻辑可以在IApplicationBuilder默认的实现类ApplicationBuilder类的Build方法中可以得知[],它的实现逻辑如下所示

public RequestDelegate Build() { //最后的管道处理,即请求未能匹配到任何终结点的情况 RequestDelegate app = context => { var endpoint = context.GetEndpoint(); var endpointRequestDelegate = endpoint?.RequestDelegate; if (endpointRequestDelegate != null) { var message = $"The request reached the end of the pipeline without executing the endpoint: '{endpoint!.DisplayName}'. " + $"Please register the EndpointMiddleware using '{nameof(IApplicationBuilder)}.UseEndpoints(...)' if using " + $"routing."; throw new InvalidOperationException(message); } //执行管道的重点是404,只有未命中任何终结点的情况下才会走到这里 context.Response.StatusCode = StatusCodes.Status404NotFound; return Task.CompletedTask; }; //_components即我们通过Use添加的中间件 foreach (var component in _components.Reverse()) { //得到执行结果即RequestDelegate app = component(app); } //返回第一个管道中间件 return app; }

通过上面的代码我们可以清楚的看到,管道最终执行的就是执行Func<RequestDelegate, RequestDelegate>这个委托的返回结果RequestDelegate。

由此得到结论,基于约定的中间件形式,通构造函数注入的服务实例,是和应用程序的生命周期一致的。通过Invoke或InvokeAsync方法注入的服务实例每次请求都会被执行到,即生命周期是Scope的。

总结

通过本次对源码的研究,我们认识到了自定义的ASP.NET Core中间件是如何被初始化的。虽然自定义的中间件的形式有许多种方式,但是最终还都是转换为IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware)这种方式。将中间件抽离为独立的类有两种方式,即基于约定的方式和实现IMiddleware接口的形式,通过分析源码我们也更深刻的了解两种方式的不同之处。基于约定的方式更灵活,它的声明周期是单例的,但是通过它的Invoke或InvokeAsync方法注入的服务实例生命周期是Scope的。实现IMiddleware接口的方式生命周期取决于自己注册服务实例时候声明的周期,而且这种方式没办法通过方法注入服务,因为有IMiddleware接口InvokeAsync方法的约束。

当然不仅仅是我们在总结中说的的这些,还存在更多的细节,这些我们在分析源码的时候都有涉及,相信阅读文章比较仔细的同学肯定会注意到这些。阅读源码收获正是这些,解决心中的疑问,了解更多的细节,有助于在实际使用中避免一些不必要的麻烦。本次讲解就到这里,愿各位能有所收获。

到此这篇关于ASP.NET Core中间件初始化的实现的文章就介绍到这了,更多相关ASP.NET Core中间件初始化内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:

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

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