![](/img/trans.png)
[英].NET Core 3 Worker Service Dependency Injection Configuration by IOptions
[英]Dependency Injection in Worker Service to classes other than Controllers by IOptions
我知道這是一個重復的問題,經歷了答案,不知道這里發生了什么。 在這個問題中,我們需要將值從appsettings.json
轉移到另一個 class 以外的控制器,這里的ServiceSettings.cs 。
這是一個類似“hello world”的示例程序,這里我們需要將值從appsettings.json
傳輸到插件。
appsettings.json
"Application": {
"TimerInterval": 10000,
"LogLevel": "Debug"
}
我根據 class 庫中的此應用程序設置創建了 class -
應用程序設置.cs
public class ApplicationSettings
{
public int TimerInterval { get; set; }
public string LogLevel { get; set; }
}
我嘗試通過最后一行代碼從 appsettings 推送數據
services.Configure<ApplicationSettings>(hostContext.Configuration.GetSection("Application"));
程序.cs
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseWindowsService()
.ConfigureServices((hostContext, services) =>
{
services.AddSingleton<IConfiguration>(hostContext.Configuration);
// Service Settings Injected here
services.AddOptions<ServiceSettings>();
services.AddHostedService<Worker>();
services.Configure<ApplicationSettings>(hostContext.Configuration.GetSection("Application"));
// for configure application
});
}
在工作人員 class 的啟動方法期間,我需要從 ServiceSettings() 獲取值,該值始終返回null
值。
Worker.cs(重新編輯)
public class Worker : BackgroundService
{
private readonly ILogger<Worker> _logger;
private readonly IConfiguration _configuration;
private ServiceSettings _settings;
public Worker(ILogger<Worker> logger, IConfiguration config)
{
_logger = logger;
_configuration = config;
}
public override Task StartAsync(CancellationToken cancellationToken)
{
Console.WriteLine("Start Asynch Method");
// Load Settings From Configuration Files
_settings = new ServiceSettings();
_settings.Load();
_logger.LogInformation("Settings: {setting}", _settings.TimerInterval);
return base.StartAsync(cancellationToken);
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
var values = _configuration.GetSection("DataSources").Get<List<DataSource>>();
while (!stoppingToken.IsCancellationRequested) {
await Task.Delay(Convert.ToInt32(_configuration["Application:TimerInterval"]), stoppingToken);
}
}
}
下面提供的服務設置值接收 null 值
服務設置.cs
public class ServiceSettings
{
private readonly IOptions<ApplicationSettings> _appSettings;
public ServiceSettings(IOptions<ApplicationSettings> appSettings)
{
_appSettings = appSettings;
}
public int TimerInterval { get; set; }
public string LogLevel { get; set; }
public void Load()
{
// Error is shown here
try { TimerInterval = Convert.ToInt32(_appSettings.Value.TimerInterval); }
catch { TimerInterval = 60; }
try
// Here too
{ LogLevel = Convert.ToString(_appSettings.Value.LogLevel).ToLower(); }
catch { LogLevel = "info"; }
}
}
我對工人服務很陌生,我在這里想念什么? 請用資源指導我謝謝大家。
這似乎是一個設計問題。
首先讓我們修復組合根。 避免注入IConfiguration
。 可以將其視為代碼異味,因為IConfiguration
理想情況下應在啟動時使用。
public class Program {
public static void Main(string[] args) {
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseWindowsService()
.ConfigureServices((hostContext, services) => {
IConfiguration config = hostContext.Configuration;
// parse settings
ApplicationSettings appSettings = config
.GetSection("Application").Get<ApplicationSettings>();
//set defaults.
if(appSettings.TimerInterval == 0)
appSettings.TimerInterval = 60;
if(string.IsNullOrWhiteSpace(appSettings.LogLevel))
appSettings.LogLevel = "Debug";
services.AddSingleton(appSettings); //<-- register settings run-time data
services.AddHostedService<Worker>();
});
}
請注意如何從配置中提取設置並將其添加到服務集合中。 由於已經有一個強定義的類型( ApplicationSettings
),根據原始問題中顯示的內容,確實不需要ServiceSettings
。
更新工作人員以明確依賴所需的實際 object。
public class Worker : BackgroundService {
private readonly ILogger<Worker> _logger;
private readonly ApplicationSettings settings;
public Worker(ILogger<Worker> logger, ApplicationSettings settings) {
_logger = logger;
this.settings = settings; //<-- settings injected.
}
public override Task StartAsync(CancellationToken cancellationToken) {
Console.WriteLine("Start Asynch Method");
_logger.LogInformation("Settings: {setting}", settings.TimerInterval);
return base.StartAsync(cancellationToken);
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken) {
while (!stoppingToken.IsCancellationRequested) {
await Task.Delay(settings.TimerInterval), stoppingToken);
}
}
}
您總是必須從您的服務集合中獲取實例。 您通常通過將它們注入 class 構造函數來執行此操作。
// WRONG
// Worker.cs
_settings = new ServiceSettings();
那么讓兩個類的數據相同, ServiceSettings
和ApplicationSettings
都一樣,這似乎是沒有意義的。 如果您需要服務注入中的應用程序設置IOptions<ApplicationSettings>
就是這樣。 如果您需要單獨的設置類,請將它們作為IOption<MyOtherSectionSettings>
提供。
最后,它可能看起來像這樣:
public class Worker {
private readonly ApplicationSettings _settings;
private readonly ILogger<Worker> _logger;
public Worker(IOptions<ApplicationSettings> settingsAccessor, ILogger<Worker> logger) {
_settings = settingsAccessor.Value;
_logger = logger;
}
public override Task StartAsync(CancellationToken cancellationToken) {
Console.WriteLine("Start Asynch Method");
_logger.LogInformation("Settings: {setting}", _settings.TimerInterval);
return base.StartAsync(cancellationToken);
}
}
請注意,讀取 settingsAccessor.Value 是框架真正嘗試訪問配置的地方,因此在這里我們應該考慮錯誤條件(如果之前未驗證)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.