本文介绍了单例服务上的ASP.NET核心调用异步初始化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一项服务,可以使用InitAsync

I have a service that asynchronously reads some content from a file in a method called InitAsync

public class MyService : IService {
    private readonly IDependency injectedDependency;

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

    public async Task InitAsync() {
        // async loading from file.
    }
}

现在此服务已注入我的控制器中.

Now this service is injected into my controller.

public class MyController : Controller {
    private readonly IService service;

    public MyController(IService service) {
        this.service = service;
    }
}

现在,我想要MyService的单例实例.我想在启动时调用InitAsync.

Now I want a singleton instance of MyService. And I want to call InitAsync in startup.

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

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

What is happening is at the time of startup, an instance of MyService is created and InitAsync() is called on it. Then when I called the controller class, another instance of MyService is created which is then reused for consequent calls.

我需要的是在启动时仅初始化一个实例,称为InitAsync(),并让它也可以被控制器重用.

What I need is to initialize only 1 instance, called InitAsync() on it in startup and have it be reused by controllers as well.

推荐答案

调用BuildServiceProvider()时,将创建一个单独的IServiceProvider实例,该实例将创建自己的IService单例实例.解决为MyController提供的IService时使用的IServiceProvider与您自己创建的IServiceProvider不同,因此IService本身也有所不同(且未初始化).

When you call BuildServiceProvider(), you create a separate instance of IServiceProvider, which creates its own singleton instance of IService. The IServiceProvider that gets used when resolving the IService that's provided for MyController is different to the one you created yourself and so the IService itself is also different (and uninitialised).

您可以在Program.Main中进行操作,而不是尝试在Startup.ConfigureServices内部解析和初始化IService.这有两件事:

Rather than attempting to resolve and initialise IService inside of Startup.ConfigureServices, you can do so in Program.Main. This allows for two things:

  1. 使用IService same 实例进行初始化和以后使用.
  2. await调用InitAsync,目前已在您所展示的方法中抛弃它.
  1. Using the same instance of IService for initialisation and later use.
  2. awaiting the call to InitAsync, which is currently fire-and-forget in the approach you've shown.

下面是Program.Main外观的一个示例:

Here's an example of how Program.Main might look:

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

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

    webHost.Run();
    // await webHost.RunAsync();
}

这使用 启用await的使用,构建IWebHost并使用其IServiceProvider解析和初始化IService.该代码还显示了如何使用awaitRunAsync(如果愿意),现在方法是async.

This uses async Main to enable use of await, builds the IWebHost and uses its IServiceProvider to resolve and initialise IService. The code also shows how you can use await with RunAsync if you prefer, now that the method is async.

这篇关于单例服务上的ASP.NET核心调用异步初始化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-11 18:10