探索ASP.NET Core中的IStartupFilter
原文: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中的IStartupFilter的更多相关文章
- 探索ASP.Net Core 3.0系列四:在ASP.NET Core 3.0的应用中启动时运行异步任务
前言:在本文中,我将介绍ASP.NET Core 3.0 WebHost的微小更改如何使使用IHostedService在应用程序启动时更轻松地运行异步任务. 翻译 :Andrew Lock ht ...
- 探索 ASP.Net Core 3.0系列三:ASP.Net Core 3.0中的Service provider validation
前言:在本文中,我将描述ASP.NET Core 3.0中新的“validate on build”功能. 这可以用来检测您的DI service provider是否配置错误. 具体而言,该功能可检 ...
- 探索ASP.Net Core 3.0系列六:ASP.NET Core 3.0新特性启动信息中的结构化日志
前言:在本文中,我将聊聊在ASP.NET Core 3.0中细小的变化——启动时记录消息的方式进行小的更改. 现在,ASP.NET Core不再将消息直接记录到控制台,而是正确使用了logging 基 ...
- 探索ASP.Net Core 3.0系列二:聊聊ASP.Net Core 3.0 中的Startup.cs
原文:探索ASP.Net Core 3.0系列二:聊聊ASP.Net Core 3.0 中的Startup.cs 前言:.NET Core 3.0 SDK包含比以前版本更多的现成模板. 在本文中,我将 ...
- ASP.NET Core中使用GraphQL - 第四章 GraphiQL
ASP.NET Core中使用GraphQL ASP.NET Core中使用GraphQL - 第一章 Hello World ASP.NET Core中使用GraphQL - 第二章 中间件 ASP ...
- Asp.net core中的依赖注入
使用服务 在Asp.net core的Controller中,可以通过如下两种方式获取系统注入的服务: 构造函数 可以直接在构造函数中传入所依赖的服务,这是非常常见的DI注入方式. public Va ...
- 探索Asp net core3中的 项目文件、Program.cs和通用host(译)
引言 原文地址 在这篇博客中我将探索一些关于Asp.net core 3.0应用的基础功能--.csproj 项目文件和Program源文件.我将会描述他们从asp.net core 2.X在默认模版 ...
- 探索ASP.NET Core 3.0系列一:新的项目文件、Program.cs和generic host
前言:在这篇文章中我们来看看ASP.Net Core 3.0应用程序中一些基本的部分—— .csproj项目文件和Program.cs文件.我将会介绍它们从 ASP.NET Core 2.x 中的默认 ...
- [转]探索ASP.NET Core 3.0 系列
这是该系列的第一篇文章:探索ASP.NET Core 3.0. 第1部分-探索新的项目文件Program.cs和通用主机(本文) 第2部分-比较ASP.NET Core 3.0模板之间的Startup ...
随机推荐
- python文件的路径问题补充上一篇内容
上次的路径问题还没解决就被勒索病毒的木马器给搞了两周多, 拖拖拖到现在又开始纠结路径问题...还是学习能力不足啊... 补充一下路径问题的知识, 毕竟jupyter notebook跟IDE测试的时候 ...
- .Net异步关键字async/await的最终理解
由于之前的项目中自己突然想试试异步action,于是使用了一下,突然就对异步action的执行流程以及原理及其好处产生了兴趣,再参考了一些文章之后,就做了下归类. 我们可以不需要太深入的理解底层,但是 ...
- linux 安装mysql5.7版本
首先准备好mysql5.7.17的安装包,安装包放在 /data/software 目录下 进入到 /usr/local 目录下,解压mysql安装包 命令: cd /usr/local tar ...
- tar解压到指定目录
对于tar.gz的压缩包,压缩参数是tar xvzf 指定解压路径为/tmp则为: tar xzvf xxx.tar.gz -C /tmp 注意/文件夹必须存在.
- Kafka 安装配置
1. 下载安装kafka 下载地址:http://apache.fayea.com/kafka/ 解压安装包 tar zxvf kafka_版本号.tgz 2. 配置 修改kafka的config/s ...
- Hive管理表分区的创建,数据导入,分区的删除操作
Hive分区和传统数据库的分区的异同: 分区技术是处理大型数据集经常用到的方法.在Oracle中,分区表中的每个分区是一个独立的segment段对象,有多少个分区,就存在多少个相应的数据库对象.而在P ...
- 读取 ini 配置文件
ini 配置文件格式:db_config.ini '''[section]option=value''' [DATABASE1] host=192.168.30.80 port= user=testa ...
- web项目部署到服务器中浏览器中显示乱码
项目部署之后浏览器打开查看时页面乱码 这里可能需要修改一下tomcat配置文件,首先找到Tomcat的安装路径下的conf/server.xml文件,找到之后可以CTRL+F搜索如下的内容: < ...
- HTTP Status 500 - Request processing failed; nested exception is org.apache.ibatis.binding.BindingException: Invalid bound statement (not found)
今天整合ssm框架 时 遇到的问题 困扰我好长时间 原因就是 mapper文件 没有被加载进来 但是 为什么没有被加载进来呢 因为中间的配置文件出了一些问题 网上大多数说法是 在pom ...
- 使用自建Git服务器管理私有项目 Centos 7.3 + Git 2.11.0 + gitosis (实测 笔记)
环境: 系统硬件:vmware vsphere (CPU:2*4核,内存2G,双网卡) 系统版本:CentOS-7-x86_64-Minimal-1611.iso GIT服务器IP:192.168.1 ...