En IServiceCollection, los métodos proporcionados para los servicios de registro AddTransiet, AddScoped, AddSingleton no le permiten el uso de la construcción async-await cuando tiene que recuperar un servicio calculando algunos de sus pasos.
Quiero saber si hacer una versión asíncrona sería un enfoque válido.
internal static IServiceCollection AddScopedResolveAsync<TService>(this IServiceCollection serviceCollection, Func<IServiceProvider, Task<TService>> func) => serviceCollection.AddScoped(func);y luego usarlo
services.AddScopedResolveAsync<IMyService>(async serviceProvider => { await something; return new MyService(); });Lo que realmente está registrando en el contenedor es Task<TService> con una vida útil limitada. Por lo tanto, sería un enfoque válido si TService no es desechable, porque el alcance no eliminará TService cuando se elimine el alcance, eliminará Task<TService>
Y para usarlo en otro servicio escribes algo como esto:
public class AnotherService { private readonly Task<MyService> _myServiceTask; public AnotherService(Task<MyService> myServiceTask) { this._myServiceTask = myServiceTask; } public async Task DoSomethingAsync() { var myService = await _myServiceTask; ...... } }La pregunta es realmente interesante, especialmente para servicios transitorios y con alcance. Para singletons, resolví este problema en un par de proyectos al completar la inicialización asíncrona en Program#Main de esta manera:
await webHost.Services.GetService<IMyService>().InitializeAsync(); He probado algunos enfoques de su caso con servicios de alcance. Como señala @pinkfloydx33, inyectar Task<IMyService> no es un enfoque muy limpio, principalmente porque los problemas de contenedores se incluyen en múltiples implementaciones, pero también porque hará que las pruebas de escritura sean más difíciles.
Otro problema que tenemos que tener en cuenta es la eliminación de instancias cuando el contenedor no se encarga de eso.
Probablemente comenzaría con una solución lo más simple posible como la siguiente, y avanzaría si hay problemas de rendimiento.
services.AddScoped<IMyService>(serviceProvider => { var someResultFromAsyncMethod = serviceProvider.GetService<IAnotherService>().AnAsyncMethod() .GetAwaiter() .GetResult(); ... return new MyService(...); });En esta respuesta, todos los problemas asincrónicos del contenedor se trasladan a la clase de servicio: https://stackoverflow.com/a/43240576/14072498
Pero, de nuevo, se complica y el precio de mantener los métodos asincrónicos puede ser elevado.