ASP.NET 核心在单例服务上调用异步初始化

use*_*951 15 c# dependency-injection asp.net-core

我有一个服务,它在一个名为的方法中从文件中异步读取一些内容 InitAsync

public class MyService : IService {
    private readonly IDependency injectedDependency;

    public MyService(IDependency injectedDependency) {
        this.injectedDependency = injectedDependency;
    }

    public async Task InitAsync() {
        // async loading from file.
    }
}
Run Code Online (Sandbox Code Playgroud)

现在这个服务被注入到我的控制器中。

public class MyController : Controller {
    private readonly IService service;

    public MyController(IService service) {
        this.service = service;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我想要一个 MyService 的单例实例。我想在启动时调用 InitAsync。

public class Startup {
    public void ConfigureServices(IServiceCollection services) {
        ......
        services.AddSingleton<IService, MyService>();
        var serviceProvider = services.BuildServiceProvider();
        // perform async init.
        serviceProvider.GetRequiredService<IService>().InitAsync();
    }
}
Run Code Online (Sandbox Code Playgroud)

发生的事情是在启动时,创建并InitAsync()调用MyService 的一个实例。然后,当我调用控制器类时,会创建另一个 MyService 实例,然后将其重用于后续调用。

我需要的是仅初始化 1 个实例,在启动时对其调用 InitAsync() 并让它也由控制器重用。

Kir*_*kin 20

发生的事情是在启动时,创建了一个 MyService 实例并在其上调用了 InitAsync()。然后,当我调用控制器类时,会创建另一个 MyService 实例,然后将其重用于后续调用。

当您调用 时BuildServiceProvider(),您创建了一个单独的 实例IServiceProvider,它创建了自己的 的单例实例IServiceIServiceProvider解决所IService提供的那个时使用的那个MyController与您自己创建的那个不同,因此它IService本身也不同(并且未初始化)。

我需要的是仅初始化 1 个实例,在启动时对其调用 InitAsync() 并让它也由控制器重用。

而不是试图解决并初始化IService里面的Startup.ConfigureServices,你可以这么做Program.Main。这允许做两件事:

  1. 使用相同的实例IService进行初始化和以后使用。
  2. await调用InitAsync,这是目前在您展示的方法中即发即忘的方法。

下面是一个示例Program.Main

public static async Task Main(string[] args)
{
    var webHost = CreateWebHostBuilder(args).Build();

    await webHost.Services.GetRequiredService<IService>().InitAsync();

    webHost.Run();
    // await webHost.RunAsync();
}
Run Code Online (Sandbox Code Playgroud)

这用于async Main启用await、构建IWebHost并使用其IServiceProvider来解析和初始化IService。如果您愿意,代码还显示了如何使用awaitwith RunAsync,现在该方法是async.