Saltar al contenido

Forma correcta de registrar HostedService en ASP.NET Core. AddHostedService frente a AddSingleton

No dudes en compartir nuestro espacio y códigos con tus amigos, necesitamos de tu ayuda para hacer crecer esta comunidad.

Solución:

Actualizar

En el pasado, un HostedService era un transitorio de larga duración que actuaba efectivamente como un singleton. Desde .NET Core 3.1 es un Singleton real.


Utilizar AddHostedService

Un servicio alojado es más que un servicio único. El tiempo de ejecución “sabe” al respecto, puede decirle que comience llamando StartAsync o pasa por llamar StopAsync() cada vez que, por ejemplo, se recicla el grupo de aplicaciones. El tiempo de ejecución puede esperar a que finalice el servicio alojado antes de que finalice la propia aplicación web.

Como la documentación explica un servicio de alcance lata consumirse creando un ámbito dentro del método de trabajo del servicio alojado. Lo mismo se aplica a los servicios transitorios.

Para hacerlo, se debe inyectar un IServicesProvider o un IServiceScopeFactory en el constructor del servicio alojado y usarlo para crear el alcance.

Tomando prestado de los documentos, el constructor del servicio y el método de trabajo pueden verse así:

public IServiceProvider Services  get; 

public ConsumeScopedServiceHostedService(IServiceProvider services, 
    ILogger logger)

    Services = services;
    _logger = logger;



private void DoWork()

    using (var scope = Services.CreateScope())
    
        var scopedProcessingService = 
            scope.ServiceProvider
                .GetRequiredService();

        scopedProcessingService.DoWork();
    

Esta pregunta relacionada muestra cómo usar un DbContext transitorio en un servicio alojado:

public class MyHostedService : IHostedService

    private readonly IServiceScopeFactory scopeFactory;

    public MyHostedService(IServiceScopeFactory scopeFactory)
    
        this.scopeFactory = scopeFactory;
    

    public void DoWork()
    
        using (var scope = scopeFactory.CreateScope())
        
            var dbContext = scope.ServiceProvider.GetRequiredService();
            …
        
    
    …

Actualizar

En algún lugar entre .Net Core 2.2 y 3.1, el comportamiento ha cambiado, AddHostedService ahora está agregando un Singleton en lugar del servicio transitorio anterior. Crédito – LeonG

public static class ServiceCollectionHostedServiceExtensions

    /// 
    /// Add an  registration for the given type.
    /// 
    /// An  to register.
    /// The  to register with.
    /// The original .
    public static IServiceCollection AddHostedService<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] THostedService>(this IServiceCollection services)
        where THostedService : class, IHostedService
    
        services.TryAddEnumerable(ServiceDescriptor.Singleton());

        return services;
    

    /// 
    /// Add an  registration for the given type.
    /// 
    /// An  to register.
    /// The  to register with.
    /// A factory to create new instances of the service implementation.
    /// The original .
    public static IServiceCollection AddHostedService(this IServiceCollection services, Func implementationFactory)
        where THostedService : class, IHostedService
    
        services.TryAddEnumerable(ServiceDescriptor.Singleton(implementationFactory));

        return services;
    

Referencia ServiceCollectionHostedServiceExtensions


Respuesta Original

Son similares pero no del todo

AddHostedService es parte de Microsoft.Extensions.Hosting.Abstractions.

Pertenece a Microsoft.Extensions.Hosting.Abstractions en el ServiceCollectionHostedServiceExtensions clase

using Microsoft.Extensions.Hosting;

namespace Microsoft.Extensions.DependencyInjection

    public static class ServiceCollectionHostedServiceExtensions
    
        /// 
        /// Add an  registration for the given type.
        /// 
        /// An  to register.
        /// The  to register with.
        /// The original .
        public static IServiceCollection AddHostedService(this IServiceCollection services)
            where THostedService : class, IHostedService
            => services.AddTransient();
    

Tenga en cuenta que está usando Transient alcance de por vida y no Singleton

Internamente, el marco agrega todos los servicios alojados a otro servicio (HostedServiceExecutor)

public HostedServiceExecutor(ILogger logger, 
    IEnumerable services) //<<-- note services collection

    _logger = logger;
    _services = services;

al inicio que es un singleton a través de WebHost Constructor.

_applicationServiceCollection.AddSingleton();

Si posees alguna suspicacia o capacidad de refinar nuestro crónica puedes ejecutar una reseña y con deseo lo interpretaremos.

¡Haz clic para puntuar esta entrada!
(Votos: 4 Promedio: 4.3)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *