ASP.NET Core框架为我们提供了两个定义明确的初始化位置:
1. Startup.ConfigureServices()
方法注册DI服务
2. Startup.Configure()
方法用于配置中间件管道
但是我的Web应用程序特有的其他初始化步骤呢?那些应该去哪儿,特别是如果它们需要注入依赖项时?
例如,我需要基于在配置文件appsettings.json中指定的连接字符串来初始化数据库ORM。因此,此初始化代码与IConfiguration
以及在Startup.ConfigureServices()
根据这些文章的建议:
我试图将初始化逻辑封装在单独的类中,然后为IWebHostBuilder
创建扩展方法以执行此代码,但是如何使框架将IConfiguration
和其他自定义依赖项注入此扩展方法中?另外,当所有依赖项都已注册时,我可以确定在Startup.ConfigureServices()
之后执行此代码吗?
是否存在一些更好或推荐的方式来执行此类任务?
答案 0 :(得分:4)
您可以为IWebHost
添加扩展方法(而不是IWebHostBuilder
),然后使用IWebHost.Services
解决服务。这是一个有关如何检索IConfiguration
的简单示例:
public static class WebHostExtensions
{
public static IWebHost SomeExtension(this IWebHost webHost)
{
var config = webHost.Services.GetService<IConfiguration>();
// Your initialisation code here.
// ...
return webHost;
}
}
此扩展方法的用法如下所示:
CreateWebHostBuilder(args)
.Build()
.SomeExtension()
.Run();
如果需要async
的{{1}}版本,则可以拆分上面的链接和SomeExtension
扩展方法。可能是这样的:
await
用法如下:
public static async Task SomeExtensionAsync(this IWebHost webHost)
{
var config = webHost.Services.GetService<IConfiguration>();
// Your initialisation code here with awaits.
// ...
}
还可以确保在所有依赖项都已注册后
public static async Task Main(string[] args) { var webHost = CreateWebHostBuilder(args) .Build(); await webHost.SomeExtensionAsync(); webHost.Run(); }
之后执行此代码吗?
使用我上面概述的方法,这里的答案是肯定的。
我认为值得指出的是Startup.ConfigureServices()
代表 root IWebHost.Services
,它将不支持解析 scoped 实例。 IServiceProvider
是一个单例,因此这不是问题,但是如果您具有作用域依赖项,则需要在扩展方法内部创建一个显式作用域。我可以提供一个示例,说明如果需要的话。
答案 1 :(得分:0)
在Program.cs
中,您的Main
方法具有以下代码:
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
运行Build()
部分后,您将拥有一个完全配置的主机。这样,您可以简单地执行以下操作:
var host = CreateWebHostBuilder(args).Build();
// do something with host
host.Run();
主机具有成员Services
,它是IServiceProvider
的实例,因此您可以从中提取所需的任何服务,即
var config = host.Services.GetRequiredService<IConfiguration>();
请记住,这时并没有固有范围,因此,如果需要范围服务,则需要创建一个范围服务:
using (var scope = host.Services.CreateScope())
{
var myScopedService = scope.ServiceProvider.GetRequiredService<MyScopedService>();
// do something with myScopedService
}