我应该在ASP.NET Core中的哪里执行自定义应用程序初始化步骤?

时间:2019-04-16 12:04:36

标签: c# asp.net-core

ASP.NET Core框架为我们提供了两个定义明确的初始化位置: 1. Startup.ConfigureServices()方法注册DI服务 2. Startup.Configure()方法用于配置中间件管道

但是我的Web应用程序特有的其他初始化步骤呢?那些应该去哪儿,特别是如果它们需要注入依赖项时?

例如,我需要基于在配置文件appsettings.json中指定的连接字符串来初始化数据库ORM。因此,此初始化代码与IConfiguration以及在Startup.ConfigureServices()

期间已注册到DI容器中的其他自定义服务有关。

根据这些文章的建议:

我试图将初始化逻辑封装在单独的类中,然后为IWebHostBuilder创建扩展方法以执行此代码,但是如何使框架将IConfiguration和其他自定义依赖项注入此扩展方法中?另外,当所有依赖项都已注册时,我可以确定在Startup.ConfigureServices()之后执行此代码吗?

是否存在一些更好或推荐的方式来执行此类任务?

2 个答案:

答案 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
}