探索ASP.NET Core中的IStartupFilter
2019-01-16 22:41
1176 查看
原文:Exploring IStartupFilter in ASP.NET Core
作者:Andrew Lock
译者:Lamond Lu
在本篇博客中,我将介绍一下
IStartupFilter, 以及如何在ASP.NET Core中使用它。在下一篇博客中,我将介绍一下如何在外部中间件中使用
IStartupFilter
IStartupFilter
接口
IStartupFilter接口存在于Microsoft.AspNetCore.Hosting.Abstractions程序集中,它非常简单,仅定义了一个接口方法。
namespace Microsoft.AspNetCore.Hosting { public interface IStartupFilter { Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next); } }
其中
Configure方法返回了一个变量
Action。
当创建一个ASP.NET Core应用程序的时候,
IApplicationBuilder负责配置ASP.NET Core的中间件管道。例如你可以在
Startup.cs文件的
Configure方法中,看到以下类似的代码。
public void Configure(IApplicationBuilder app) { app.UseStaticFiles(); app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); }); }
在这个方法中,你可以直接使用方法提供的
IApplicationBuilder参数,并且可以向其中添加各种中间件。使用
IStartupFilter, 你可以指定并返回一个
Action类型的泛型委托,这意味你除了可以使用方法提供的泛型委托配置
IApplicationBuilder对象, 还需要返回一个泛型委托。
IStartupFilter方法可以接受一个配置
IApplicationBuilder的方法,换而言之
IStartupFilter.Configure方法可以使用
Startup.Configure方法作为参数。
例:
Startup _startup = new Startup(); Action<IApplicationBuilder> startupConfigure = _startup.Configure; //后续会补充StartupFilter1类的代码 IStartupFilter filter1 = new StartupFilter1(); Action<IApplicationBuilder> filter1Configure = filter1.Configure(startupConfigure) //后续会补充StartupFilter2类的代码 IStartupFilter filter2 = new StartupFilter2(); Action<IApplicationBuilder> filter2Configure = filter2.Configure(filter1Configure)
如果之前你学习过ASP.NET Core的中间件管道,对于这个代码,你可能会感觉很熟悉。这里我们正在建立另一条管道, 它是一个Configure方法的管道,而不是中间件管道。 这就是
IStartupFilter的目的,允许在应用程序中创建
Configure方法的管道。
实现IStartupFilter
接口的对象何时会被调用?
现在我们对
IStartupFilter的签名有了更进一步的理解,接下来我们可以看看它在ASP.NET Core框架中的用法。
要查看
IStartupFilter是如果被调用的,你可以在查看Microsoft.AspNetCore.Hosting程序集中的
WebHost类。 当你在
WebHostBuilder对象上调用
Build方法时,实现
IStartupFilter接口对象会被调用。 这个代码通常出现在
Program.cs文件中,例如:
public class Program { public static void Main(string[] args) { var host = new WebHostBuilder() .UseKestrel() .UseContentRoot(Directory.GetCurrentDirectory()) .UseStartup<Startup>() .Build(); // 这个会调用BuildApplication方法 host.Run(); } }
下面是
BuildApplication方法的部分代码,你可以看到这个方法负责初始化中间件管道。方法的返回值
RequestDelegate表示了一个完整的管道,当请求到达的时候,Kestral服务器可以调用它。
private RequestDelegate BuildApplication() { .. IApplicationBuilder builder = builderFactory.CreateBuilder(Server.Features); builder.ApplicationServices = _applicationServices; var startupFilters = _applicationServices.GetService<IEnumerable<IStartupFilter>>(); Action<IApplicationBuilder> configure = _startup.Configure; foreach (var filter in startupFilters.Reverse()) { configure = filter.Configure(configure); } configure(builder); return builder.Build(); }
首先,此方法创建
IApplicationBuilder的实例,该实例将用于构建中间件管道,并将
ApplicationServices设置为已配置的DI容器。
接下来的代码块很意思。首先,从DI容器中获取了一个集合
IEnumerable<IStartupFilter。正如我前面说的那样,我们可以配置多个
IStartupFilter来形成一个管道,所以这个方法只是从容器中取出它们。此外,
Startup.Configure方法被保存到局部变量
configure中, 这就是通常在
Startup类中编写的
Configure方法,用于配置中间件管道。
现在我们通过循环遍历每个
IStartupFilter(以相反的顺序),传入
Startup.Configure方法,然后更新局部变量
configure来创建Configure方法的管道。这种方式实现了一种嵌套管道的效果。例如,如果我们有三个
IStartupFilter实例,你最终会得到类似这样的东西,其中内部
Configure方法在参数中传递给外部方法:
局部变量
configure的最终值会被
IApplicationBuilder调用来执行实际的中间件管道配置。 调用
builder.Build方法之后会生成处理HTTP请求所需的
RequestDelegate。
一个IStartupFilter
的例子
前面我虽然描述了
IStartupFilter的用途,但是可能查看一些现成的实现会更容易理解一些。 默认情况下,
WebHostBuilder在初始化时会注册一个
IStartupFilter-
AutoRequestServicesStartupFilter
public class AutoRequestServicesStartupFilter : IStartupFilter { public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next) { return builder => { builder.UseMiddleware<RequestServicesContainerMiddleware>(); next(builder); }; } }
本质上,它在中间件管道的开头添加了一个额外的中间件,即
RequestServicesContainerMiddleware。
这是唯一一个默认注册的
IStartupFilter,因此在这种情况下,参数
next将是
Startup类的
Configure方法。
这基本上就是
IStartupFilter的全部内容 - 它是一种在配置的管道的开头或结尾添加额外中间件(或其他配置)的方法。
如何注册IStartupFilter
注册
IStartupFilter很简单,只需像往常一样在你的ConfigureServices方法中注册它。 默认情况下,在
WebHostBuilder中已经注册了
AutoRequestServicesStartupFilter
private IServiceCollection BuildHostingServices() { ... services.AddTransient<IStartupFilter, AutoRequestServicesStartupFilter>(); ... }
RequestServicesContainerMiddleware
中间件
以下是
RequestServicesContainerMiddleware的部分代码
public class RequestServicesContainerMiddleware { private readonly RequestDelegate _next; private IServiceScopeFactory _scopeFactory; public RequestServicesContainerMiddleware(RequestDelegate next, IServiceScopeFactory scopeFactory) { _scopeFactory = scopeFactory; _next = next; } public async Task Invoke(HttpContext httpContext) { var existingFeature = httpContext.Features.Get<IServiceProvidersFeature>(); if (existingFeature?.RequestServices != null) { await _next.Invoke(httpContext); return; } using (var feature = new RequestServicesFeature(_scopeFactory)) { try { httpContext.Features.Set<IServiceProvidersFeature>(feature); await _next.Invoke(httpContext); } finally { httpContext.Features.Set(existingFeature); } } } }
该中间件负责设置
IServiceProvidersFeature。 创建时,
RequestServicesFeature为请求创建新的
IServiceScope和
IServiceProvider。 它将负责使用Scoped生命周期添加到DI容器的依赖项的创建和处理。
IStartupFilter
的使用场景
一般来说,我不认为在用户的应用程序中需要使用
IStartupFilter。 就其本质而言,用户可以在
Configure方法中定义中间件管道,因此
IStartupFilter是不必要的。
我能想到以下几种需要使用
IStartupFilter的场景:
- 你自己创建了一个库,你需要确保你的中间件在中间件管道的开头(或结尾)运行。
- 你正在使用一个使用
IStartupFilter
的库,您需要确保您的中间件在它之前运行。
总结
本篇博文中,我讲解了
IStartupFilter以及
WebHost如何使用它在构建中间件管道。 在下一篇文章中,我将探讨
IStartupFilter的具体用法。
后记
本篇是作者早期的一篇博文,个人觉着对
IStartupFilter讲解的比较清楚,就翻译了一下。在作者的后期博文中,作者提供了许多
IStartupFilter的使用场景,例如
- 在ASP.NET Core项目启动前,使用
IStartupFilter
验证强类型配置 - 在ASP.NET Core项目启动前,使用
IStartupFilter
进行数据库迁移和缓存预读取
有兴趣的同学可以自己阅读一下,后续我会选择一些有意思的文章翻译一下。
相关文章推荐
- ASP.NET Core 运行原理剖析2:Startup 和 Middleware(中间件)
- [转]Create Custom Exception Filter in ASP.NET Core
- Asp.net Core Startup Class中是如何获取配置信息的
- ASP.NET Core 菜鸟之路:从Startup.cs说起
- ASP.NET CORE基础教程(一)-启动文件Startup
- ASP.NET Core 菜鸟之路:从Startup.cs说起
- ASP.NET Core MVC/WebAPi 模型绑定探索
- 使用Code First建模自引用关系笔记 asp.net core上使用redis探索(1) asp.net mvc控制器激活全分析 语言入门必学的基础知识你还记得么? 反射
- ASP.NET Core 运行原理剖析2:Startup 和 Middleware(中间件)
- ASP.NET Core MVC/WebAPi 模型绑定探索(转载)
- 使用Visual Studio Code开发Asp.Net Core WebApi学习笔记(五)-- Filter
- 学习ASP.NET Core, 怎能不了解请求处理管道[4]: 应用的入口——Startup
- 学习ASP.NET Core, 怎能不了解请求处理管道[5]: 中间件注册可以除了可以使用Startup之外,还可以选择StartupFilter
- ASP.NET Core 2.0系列学习笔记-启动类Startup
- ASP.NET Core MVC/WebAPi 模型绑定探索
- ASP.NET Core中的ActionFilter与DI
- ASP.NET Core 运行原理剖析2:Startup 和 Middleware(中间件)
- 【asp.net Core 2.0 初步探索】
- ASP.NET Core 1.0 入门——Application Startup¶
- Do you kown Asp.Net Core -- 配置Kestrel端口