将参数传递给AddHostedService

时间:2019-07-15 21:53:31

标签: c# asp.net-core .net-core windows-services

我正在编写.Net Core Windows服务,他是一些代码段

internal static class Program
    {
        public static async Task Main(string[] args)
        {
            var isService = !(Debugger.IsAttached || args.Contains("--console"));

            var builder = new HostBuilder()
                .ConfigureServices((hostContext, services) =>
                {
                    services.AddHostedService<IntegrationService>();
                });

            if (isService)
            {
                await builder.RunAsServiceAsync();
            }
            else
            {
                await builder.RunConsoleAsync();
            }
        }
    } 

我想将一些参数传递给我的服务,即IntegrationService如何将参数发送给服务。

4 个答案:

答案 0 :(得分:1)

.net core 3之前,您可以使用可通过DI注入到服务中的配置类。

您的配置类如下所示:

class IntegrationConfig
{
    public int Timeout { get; set; }
    public string Name { get; set; }
}

然后您需要将此配置添加到DI系统:

services.AddSingleton(new IntegrationConfig
{
    Timeout = 1234,
    Name = "Integration name"
});

在类IntegrationService中,您需要添加一个接受配置对象的构造函数:

public IntegrationService(IntegrationConfig config)
{
    // setup with config or simply store config
}

基本上就是您所需要的。在我看来和.net core 3中,这不是最漂亮的解决方案 您可以简单地使用工厂函数来添加HostedService,但我认为类似的选择是最佳选择 如果您使用的是.net core 2.2或以下版本。

编辑:

柯克·拉金(Kirk Larkin)在评论中提到了这一点:

  

您可以模拟过载。它只是AddTransient()的包装,它当然支持工厂函数方法。

为此,您可能要查看here可访问的当前过载:

/// <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>
/// <param name="implementationFactory">A factory to create new instances of the service implementation.</param>
/// <returns>The original <see cref="IServiceCollection"/>.</returns>
public static IServiceCollection AddHostedService<THostedService>(this IServiceCollection services, Func<IServiceProvider, THostedService> implementationFactory)
    where THostedService : class, IHostedService
{
    services.TryAddEnumerable(ServiceDescriptor.Singleton<IHostedService>(implementationFactory));

    return services;
}

请注意,last commit that changed this file于6月3日发布,并被标记为.net core 3的Preview6和Preview7。因为我从未听说过TryAddEnumerable并且不是Microsoft员工,所以我没有知道您是否可以直接翻译。

仅通过查看current implementation of AddTransient并深入兔子的几个文件,可悲的是,我无法画出足够的线条来为您提供当前可以获得的确切功能与.net core 3
我提供的解决方法仍然有效,并且根据情况似乎可以接受。

答案 1 :(得分:1)

.NET Core 3的Joelius答案的小更新

使用此构造函数混合参数(TimeSpan和服务(ILogger<StatusService>IHttpClientFactory)来提供HostedService

public IntegrationService(
            TimeSpan cachePeriod,
            ILogger<StatusService> logger,
            IHttpClientFactory clientFactory)

您可以像这样在Startup.cs中将其添加到HostedService中:

services.AddHostedService 
    (serviceProvider => 
        new StatusService(
            TimeSpan.FromDays(1), 
            serviceProvider.GetService<ILogger<StatusService>>(), 
            serviceProvider.GetService<IHttpClientFactory>()));

答案 2 :(得分:1)

虽然以上答案是正确的,但它们确实具有您不能再在服务构造函数中使用DI的缺点。

我所做的是:

class Settings {
  public string Url { get; set; }
}
class SomeService : IHostedService {
  public SomeService (string instanceId, IOptionsMonitor<Settings> optionsMonitor) {
    var settings = optionsMonitor.Get(instanceId);
  }
}
services.Configure<Settings>("Instance1", (s) => s.Url = "http://google.com");
services.Configure<Settings>("Instance2", (s) => s.Url = "http://facebook.com");

services.AddSingleton<IHostedService>(x => 
 ActivatorUtilities.CreateInstance<SomeService>(x, "Instance1")
);

services.AddSingleton<IHostedService>(x => 
 ActivatorUtilities.CreateInstance<SomeService>(x, "Instance2")
);

这将为每个实例创建命名设置,并将命名设置名称传递给HostedService。 如果您想要多个具有相同类和不同参数的服务,请确保使用 AddSingleton 而不是 AddHostedService ,因为AddHostedService将仅添加一个相同类型的实例,这只会导致一个实例正在启动!

答案 3 :(得分:0)

尽管有另一种方法,乔利乌斯的回答是正确的

services.AddSingleton<IHostedService>(provider => new IntegrationService("Test"));