在ASP.NET Core中注册HostedService的正确方法。 AddHostedService与AddSingleton

时间:2018-07-23 13:44:15

标签: c# asp.net-core .net-core asp.net-core-2.1 asp.net-core-hosted-services

在ASP.NET Core 2.1中注册自定义托管服务的正确方法是什么?例如,我有一个源自BackgroundService的自定义托管服务,名为MyHostedService。我应该如何注册?

public IServiceProvider ConfigureServices(IServiceCollection services)
{           
    //...
    services.AddSingleton<IHostedService, MyHostedService>();
}

public IServiceProvider ConfigureServices(IServiceCollection services)
{           
    //...
    services.AddHostedService<MyHostedService>();
}

Here我们可以看到第一种情况,但是here有第二种情况。

这些方法相等吗?

2 个答案:

答案 0 :(得分:14)

使用AddHostedService

托管服务不仅仅是单例服务。运行时“知道”它,可以告诉它是通过调用StartAsync开始还是通过调用StopAsync()停止,例如在回收应用程序池时。在Web应用程序本身终止之前,运行时可以等待托管服务完成。

作为the documentation explains,可以通过在托管服务的worker方法中创建作用域来使用作用域服务 。临时服务也是如此。

为此,必须将IServicesProvider或IServiceScopeFactory注入托管服务的构造函数中,并用于创建作用域。

借用文档,该服务的构造函数和worker方法可以如下所示:

public IServiceProvider Services { get; }

public ConsumeScopedServiceHostedService(IServiceProvider services, 
    ILogger<ConsumeScopedServiceHostedService> logger)
{
    Services = services;
    _logger = logger;
}


private void DoWork()
{
    using (var scope = Services.CreateScope())
    {
        var scopedProcessingService = 
            scope.ServiceProvider
                .GetRequiredService<IScopedProcessingService>();

        scopedProcessingService.DoWork();
    }
}

This related question显示了如何在托管服务中使用瞬态DbContext:

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<MyDbContext>();
            …
        }
    }
    …
}

答案 1 :(得分:6)

它们相似但不完全

AddHostedServiceMicrosoft.Extensions.Hosting.Abstractions的一部分。

它属于ServiceCollectionHostedServiceExtensions类中的Microsoft.Extensions.Hosting.Abstractions

using Microsoft.Extensions.Hosting;

namespace Microsoft.Extensions.DependencyInjection
{
    public static class ServiceCollectionHostedServiceExtensions
    {
        /// <summary>
        /// Add an <see cref="IHostedService"/> registration for the given type.
        /// </summary>
        /// <typeparam name="THostedService">An <see cref="IHostedService"/> to register.</typeparam>
        /// <param name="services">The <see cref="IServiceCollection"/> to register with.</param>
        /// <returns>The original <see cref="IServiceCollection"/>.</returns>
        public static IServiceCollection AddHostedService<THostedService>(this IServiceCollection services)
            where THostedService : class, IHostedService
            => services.AddTransient<IHostedService, THostedService>();
    }
}

请注意,它使用的是Transient生存时间范围,而不是Singleton

内部,框架将所有托管服务添加到另一个服务(HostedServiceExecutor)

public HostedServiceExecutor(ILogger<HostedServiceExecutor> logger, 
    IEnumerable<IHostedService> services) //<<-- note services collection
{
    _logger = logger;
    _services = services;
}

在启动时是通过WebHost Constructor的单例。

_applicationServiceCollection.AddSingleton<HostedServiceExecutor>();