Передать в BackgroundService параметр
Есть BackgroundService. Как передать в него int-овый параметр? Т.е. в Setup файле получаю из appsettings переменную и хочу её передать сервису при регистрации.
public class TestService : BackgroundSerice
{
private readonly IServiceProvider _serviceProvider;
// Нужно передать someValue при регистрации сервиса
public TestService(IServiceProvider serviceProvider, int someValue)
{
_serviceProvider = serviceProvider;
}
//...
}
Обычная регистрация выполняется так (если не надо передавать someValue):
builder.Services.AddHostedService<TestService>();
Ответы (2 шт):
Если я правильно понимаю, то вот так можно. Я использую статический сервис с настройками appsettings
{
"MySettings": {
"SomeValue": 42 //наше int-овое значение
}
}
namespace VashProject.AppSettings
{
public static class ApplicationServicesSettings
{
public const string MySettings = "MySettings";
public static MyClassValue MyClassValue { get; set; } = new MyClassValue();
}
public class MyClassValue
{
public int SomeValue { get; set; }
}
}
Program
builder.Configuration.GetSection(ApplicationServicesSettings.MySettings)
.Bind(ApplicationServicesSettings.MyClassValue);
builder.Services.AddHostedService(serviceProvider =>
new TestService(serviceProvider, ApplicationServicesSettings.MyClassValue.SomeValue));
Допустим, у нас есть такой сервис:
public class TestService(IServiceProvider serviceProvider, int value) : IHostedService
{
public async Task StartAsync(CancellationToken cancellationToken)
{
while (true)
{
Console.WriteLine(value);
await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
}
}
public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
}
Наша задача передать в него int value
, вопрос.. Как?
Вариантов несколько:
Передать это значение при регистрации, сделав что-то такое:
builder.Services.AddHostedService(serviceProvider=> new TestService(serviceProvider, 1000));
Тут мы регистрируем не тип, который будет за нас создан, а уже полноценный экземпляр класса, который мы заполняем самостоятельно нужными данными.
Для красоты, можем сделать свой метод расширения:
public static class Extensions { public static IServiceCollection AddTestService(this IServiceCollection services, int value) { services.AddHostedService(ServiceProvider => new TestService(ServiceProvider, value); return services; } }
Тогда регистрация будет простой
builder.Services.AddTestService(1000);
. Если настроек много, то передавайтеAction<>
, тогда будет стандартноеAddTestService (options => { options.Value = ...; })
Мы можем сделать класс, который будет хранить в себе нужные данные и запрашивать через DI уже его. Один из вариантов пусть будет таким:
public class TestServiceSettings { public int Value { get; set; } = 1000; }
В сервисе запрашиваем этот класс:
public class TestService(..., TestServiceSettings settings) : IHostedService { public async Task StartAsync(CancellationToken cancellationToken) { ... Console.WriteLine(settings.Value); ... } ... }
Ну и регистрация пусть будет такой:
builder.Services.AddScoped<TestServiceSettings>(); builder.Services.AddHostedService<TestService>();
Все, дальше за нас все инициализирует и внедрит DI контейнер. Пример конечно так себе, но на деле класс с настройками может работать так, как вам надо, хоть получайте настройки с сервера.
Раз уж затронули настройки, то можно использовать тогда и их.
Создаем файл с нужными настройками, допустим, пусть это будет
config.json
:{ "TestServiceOptions": { "SomeInt": 101 } }
Регистрируем его:
builder.Configuration.AddJsonFile("config.json");
Дальше используем в сервисе, пробросив туда зависимость
IConfiguration configuration
, ну и в нужном месте читаем нужную настройкуconfiguration["TestServiceOptions:SomeInt"]
.Если нам надо, чтоб данные динамично менялись при изменении настроек в файле, то при регистрации конфигурации устанавливаем
reloadOnChange
(.AddJsonFile("config.json", true, reloadOnChange: true)
).Ну а для удобства работы со всем этим, применяем паттерн настроек (
IOptions
):Создаем класс, который будет соответствовать настройкам:
public class TestServiceOptions { public int SomeInt { get; set; } }
Настраиваем
IOptions
после регистрации файла:builder.Services.Configure<TestServiceOptions>(builder.Configuration.GetSection(nameof(TestServiceOptions)));
Применяем в сервисе, пробросив туда
IOptions<TestServiceOptions> options
и в нужном местеoptions.Value.SomeInt
.Но тут учтите, с автоматическим обновлением значения из файла нужно будет повозиться немного, это уже оставлю вам.
Собственно, вот вам 3 разных подхода, берите любой и используйте. Тут конечно есть еще варианты, но это по сути основные.