如何将环境变量映射到dotnet IHostedService中的配置对象?



我在一段时间内第一次创建一个新的控制台应用程序,我正在学习如何使用ihostdservice。如果我想要appsettings中的值。Json可用于我的应用程序,现在正确的方法似乎是这样做:

public static async Task Main(string[] args)
{
await Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<MyHostedService>();
services.Configure<MySettings(hostContext.Configuration.GetSection("MySettings"));
services.AddSingleton<MySettings>(container =>
{
return container.GetService<IOptions<MySettings>>().Value;
});
})
.RunConsoleAsync();
}
public class MyHostedService
{
public MyHostedService(MySettings settings)
{
// values from MySettings should be available here
}
}
public class MySettings
{
public string ASetting {get; set;}
public string AnotherSetting {get; set; }
}
// appsettings.json
{  
"MySettings": {
"ASetting": "a setting value",
"AnotherSetting":  "another value"
}
}

这很有效,很好。然而,如果我想获得我的变量,而不是从应用程序。Json节,但从环境变量?我能看到它们在hostContext中可用。配置和我可以得到单独的值配置。getvalue。但是我需要他们在myhostdservice

我尝试在本地创建它们(即作为Windows中的用户变量),使用双下划线格式,即MySettings_ASetting,但它们似乎不可用或覆盖应用设置。json值。

我想这意味着将它们映射到像MySettings这样的对象,并通过DI以同样的方式传递它,但我不确定如何做到这一点,是否有一个相当于GetSection,或者我是否需要命名我的变量不同,让他们拿起来?

如果您将环境变量声明为ASettingAnotherSetting,那么在ConfigureServices中,您将需要向持有环境变量的完整IConfiguration添加绑定,而不仅仅是对具有MySettings节名/路径的一个绑定,因为该名称/路径也被考虑到查找相应的环境变量-请参阅下面的替代方法。

下面的扩展方法来自Microsoft.Extensions.DependencyInjection版本7.0.0,它运行在。net 6上,参见文档。

services.AddOptions<MySettings>()
.BindConfiguration("MySettings") // Binds to the appsettings section.
.Bind(hostContext.Configuration); // Binds to e.g. the environment variables.

完整代码:

await Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<MyHostedService>();

services.AddOptions<MySettings>()
.BindConfiguration("MySettings")
.Bind(hostContext.Configuration);
services.AddSingleton<MySettings>(container =>
{
return container.GetService<IOptions<MySettings>>().Value;
});
})
.RunConsoleAsync();

或者,您可以将这些环境变量声明为MySettings:AnotherSettingMySettings:AnotherSetting,在这种情况下,它足以进行以下调用之一:

services.AddOptions<MySettings>().BindConfiguration("MySettings");

或者您已经拥有的代码,没有Bind(hostContext.Configuration)

services.Configure<MySettings>(hostContext.Configuration.GetSection("MySettings"));

Edit:

这段代码有问题:

services.AddSingleton<MySettings>(container =>
{
return container.GetService<IOptions<MySettings>>().Value;
});

调用GetService将构建服务提供者,但随后您将尝试向服务提供者添加一个单例。这行不通。你应该在服务中注入IOptions<MySettings>,而不是。


编辑2:

根据我的经验,双下划线不能很好地工作,如果可以的话,更喜欢使用冒号分隔的键,如MySettings:AnotherValue


一个更现代的答案:

MySettings.cs

public class MySettings
{
// Add default configuration path so it can be reused elsewhere
public const string DefaultSectionName = "MySettings";
public string AnotherSetting { get; set; } = string.Empty;
public string ASetting { get; set; } = string.Empty;
}

MyHostedService.cs

public class MyHostedService : IHostedService
{
private readonly MySettings settings;
// IOptions<TOptions> or IOptionsMonitor<TOptions>
// these interfaces add useful extensions features
public MyHostedService(IOptions<MySettings> settings)
{
this.settings = settings.Value;
}
// IHostedService Implementation redacted
}

Progam.cs

// Use top-level statements, linear and fluent service declaration:
var builder = Host.CreateApplicationBuilder(args);
builder.Services
// Declare MyHostedService as a HostedService in the DI engine
.AddHostedService<MyHostedService>()
// Declare IOption<MySettings> (and variants) in the DI engine
.AddOptions<MySettings>()
// Bind the options to the "MySettings" section of the config
.BindConfiguration(MySettings.DefaultSectionName);
await builder.Build().RunAsync();

从命令行或环境中读取设置

默认情况下,主机构建器支持从环境变量加载配置:

属性/launchSettings.json

{
"profiles": {
"run": {
"commandName": "Project",
"environmentVariables": {
"MySettings:AnotherSetting": "test-another"
}
}
}
}

Host.CreateDefaultBuilder不同,Host.CreateApplicationBuilder也支持从CLI加载配置。您可以使用dotnet run --MySettings:AnotherSetting test来覆盖应用设置的内容。json文件。请注意,在CLI中设置该变量将覆盖环境变量的值。

如果您不想从应用程序设置中获取变量。但是从环境变量中,你可以添加ConfigureAppConfiguration部分或/和ConfigureHostConfiguration到Host

await Host
.CreateDefaultBuilder(args)
.ConfigureHostConfiguration((config) =>
{
config.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("hostsettings.json", optional: true)
.AddEnvironmentVariables(prefix: "PREFIX_");
})
.ConfigureAppConfiguration((hostContext, configBuilder) =>
{
configBuilder
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json") 
// or 
.AddJsonFile($"appsettings.{hostContext.HostingEnvironment.EnvironmentName}.json", 
optional: true, reloadOnChange: true) 
//or just any name explicitly
.AddJsonFile(@"C:...mySettings.json")
.Build();
})
.ConfigureServices((hostContext, services) =>
{
services.Configure<MySettings>(hostContext.Configuration.GetSection("MySettings"));
services.AddHostedService<MyHostedService>();
})
.RunConsoleAsync();

和服务

public class MyHostedService : IHostedService
{
private readonly MySettings _settings;
public MyHostedService(IOptions<MySettings> settings)
{
_settings = settings.Value;
}
public Task StartAsync(CancellationToken cancellationToken) {};
public Task StopAsync(CancellationToken cancellationToken) {};
}

相关内容

  • 没有找到相关文章

最新更新