web-dev-qa-db-fra.com

ASP.NET core call async init sur service singleton

J'ai un service qui lit de manière asynchrone du contenu d'un fichier dans une méthode appelée InitAsync

public class MyService : IService {
    private readonly IDependency injectedDependency;

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

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

Maintenant, ce service est injecté dans mon contrôleur.

public class MyController : Controller {
    private readonly IService service;

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

Maintenant, je veux une instance singleton de MyService. Et je veux appeler InitAsync au démarrage.

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

Ce qui se passe est au moment du démarrage, une instance de MyService est créée et InitAsync() est appelée dessus. Ensuite, lorsque j'ai appelé la classe contrôleur, une autre instance de MyService est créée qui est ensuite réutilisée pour les appels conséquents.

Ce dont j'ai besoin est d'initialiser une seule instance, appelée InitAsync () sur elle au démarrage et de la faire réutiliser également par les contrôleurs.

8
user3740951

Ce qui se passe est au moment du démarrage, une instance de MyService est créée et InitAsync () est appelée dessus. Ensuite, lorsque j'ai appelé la classe contrôleur, une autre instance de MyService est créée qui est ensuite réutilisée pour les appels conséquents.

Lorsque vous appelez BuildServiceProvider(), vous créez une instance distincte de IServiceProvider, qui crée sa propre instance singleton de IService. Le IServiceProvider qui est utilisé lors de la résolution du IService fourni pour MyController est différent de celui que vous avez créé vous-même et donc le IService lui-même est également différent ( et non initialisé).

Ce dont j'ai besoin, c'est d'initialiser une seule instance, appelée InitAsync () sur elle au démarrage et de la faire réutiliser également par les contrôleurs.

Plutôt que d'essayer de résoudre et d'initialiser IService à l'intérieur de Startup.ConfigureServices, vous pouvez le faire dans Program.Main. Cela permet deux choses:

  1. Utilisation de même instance de IService pour l'initialisation et l'utilisation ultérieure.
  2. awaiten appelant à InitAsync, qui est actuellement ignoré dans l'approche que vous avez montrée.

Voici un exemple de la façon dont Program.Main pourrait ressembler:

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

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

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

Cela utilise async Main pour activer l'utilisation de await, construit le IWebHost et utilise son IServiceProvider pour résoudre et initialiser IService. Le code montre également comment vous pouvez utiliser await avec RunAsync si vous préférez, maintenant que la méthode est async.

8
Kirk Larkin