将参数传递给 AddHostedService

Ars*_*aiz 8 c# windows-services .net-core asp.net-core

我正在编写一个 .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();
            }
        }
    } 
Run Code Online (Sandbox Code Playgroud)

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

Wol*_*rit 20

虽然上面的答案是正确的,但它们确实有一个缺点,即您无法再在服务构造函数中使用 DI。

我所做的是:

class Settings {
  public string Url { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
class SomeService : IHostedService {
  public SomeService (string instanceId, IOptionsMonitor<Settings> optionsMonitor) {
    var settings = optionsMonitor.Get(instanceId);
  }
}
Run Code Online (Sandbox Code Playgroud)
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")
);
Run Code Online (Sandbox Code Playgroud)

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

  • 当您的班级需要 ILogger 和 IOptions 之类的东西时,这可以说是最好的解决方案 (2认同)

rfr*_*ebe 9

关于 .Net Core 3 的 Joelius 答案的小更新

给定一个带有此构造函数的 HostedService 混合参数 ( TimeSpan) 和服务 ( ILogger<StatusService>, IHttpClientFactory)

public StatusService(
            TimeSpan cachePeriod,
            ILogger<StatusService> logger,
            IHttpClientFactory clientFactory)
Run Code Online (Sandbox Code Playgroud)

您可以在 Startup.cs 中将其添加到 HostedService 中,如下所示:

services.AddHostedService 
    (serviceProvider => 
        new StatusService(
            TimeSpan.FromDays(1), 
            serviceProvider.GetService<ILogger<StatusService>>(), 
            serviceProvider.GetService<IHttpClientFactory>()));
Run Code Online (Sandbox Code Playgroud)


Joe*_*ius 5

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

您的配置类可能如下所示:

class IntegrationConfig
{
    public int Timeout { get; set; }
    public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

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

services.AddSingleton(new IntegrationConfig
{
    Timeout = 1234,
    Name = "Integration name"
});
Run Code Online (Sandbox Code Playgroud)

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

public IntegrationService(IntegrationConfig config)
{
    // setup with config or simply store config
}
Run Code Online (Sandbox Code Playgroud)

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

编辑:

Kirk Larkin 在评论中提到了这一点:

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

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

/// <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;
}
Run Code Online (Sandbox Code Playgroud)

请注意,更改此文件的最后一次提交是在 6 月 3 日,并被标记为 .net core 3 的预览6 和预览7。因为我从未听说过TryAddEnumerable并且不是微软员工,所以我不知道您是否可以直接翻译它。

仅通过查看当前的实现AddTransient并深入研究几个文件,遗憾的是我无法很好地绘制界限,无法为您提供当前能够获得的确切功能.net core 3
我给出的解决方法仍然有效,并且根据具体情况似乎可以接受。


Ars*_*aiz 5

Joelius 的回答是正确的,尽管还有另一种方法可以做到这一点

services.AddSingleton<IHostedService>(provider => new IntegrationService("Test"));
Run Code Online (Sandbox Code Playgroud)

  • 这可能会为您提供大部分功能,但是您能保证这会为您提供与“AddHostedService”完全相同的行为吗?通过查看源代码,我无法确认这些调用是否相等:/ (2认同)
  • 是的,它提供与“AddHostedService”相同的行为 (2认同)