I am writing a .Net Core windows service and here is a snippet of code:
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();
}
}
}
I want to pass some parameters to my service i.e. IntegrationService
- how I can send parameters to my service?
Small update on Joelius answer for .Net Core 3
Given an HostedService with this constructor mixing parameters (TimeSpan
) and services (ILogger<StatusService>
, IHttpClientFactory
)
public StatusService(
TimeSpan cachePeriod,
ILogger<StatusService> logger,
IHttpClientFactory clientFactory)
You can in your Startup.cs add it to your HostedService like this :
services.AddHostedService
(serviceProvider =>
new StatusService(
TimeSpan.FromDays(1),
serviceProvider.GetService<ILogger<StatusService>>(),
serviceProvider.GetService<IHttpClientFactory>()));
While the answers above are correct, they do have the downside that you can't use DI in the Services Constructor anymore.
What I did instead was:
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")
);
This creates named settings for each instance and passes the named settings name to the HostedService. If you want multiple Services with the same Class and different parameters make sure to use AddSingleton instead of AddHostedService as AddHostedService will add only one instance of the same Type which will result in only one instance being started!
What Joelius answered is correct although there is another way of doing this
services.AddSingleton<IHostedService>(provider => new IntegrationService("Test"));
Before .net core 3
you can use a config class which you can inject into the service via DI.
Your config class could look like this:
class IntegrationConfig
{
public int Timeout { get; set; }
public string Name { get; set; }
}
Then you need to add this config to the DI-system:
services.AddSingleton(new IntegrationConfig
{
Timeout = 1234,
Name = "Integration name"
});
In the class IntegrationService
you need to add a constructor which takes an object of the config:
public IntegrationService(IntegrationConfig config)
{
// setup with config or simply store config
}
That's basically all you need. It's not the prettiest solution in my opinion and in .net core 3
you can simply use a factory func to add the HostedService but I think something like this is the best choice
if you're on .net core 2.2
or below.
EDIT:
In the comments Kirk Larkin mentions this:
You can emulate the overload. It's just a wrapper around AddTransient(), which of course does support the factory func approach.
For this you might want to look at the current overload which is accessable 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;
}
Note that the last commit that changed this file was on June 3rd and is tagged for preview6 and preview7 of .net core 3. Because I've never heard of TryAddEnumerable
and am no microsoft employee, I don't know if you can directly translate that.
Just from looking at the current implementation of AddTransient
and going down the rabbit hole a few files more, I sadly can't draw the lines well enough to be able to give you the exact functionality you're currently able to get with .net core 3
.
The workaround I gave still works and seems acceptable depending on the situation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With