ASP.net Core 2.0中的appsettings.json预览配置GetSection null

ryc*_*moj 14 c# configuration json .net-core

我试图GetSection从注入的配置调用Startup.cs.值是null,而indexer具体部分值返回non-null值.在我看来这个GetSection方法背后的错误或我错了吗?

appsettings.json:

{"MyConfig":{"ConfigA":"valueA","ConfigB":"valueB"}}

Program.cs中:

    public static void Main(string[] args)
    {
        var host = BuildWebHost(args);
        host.Run();
    }

    public static IWebHost BuildWebHost(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>()
            .Build();
Run Code Online (Sandbox Code Playgroud)

Startup.cs:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        var mySection = this.Configuration.GetSection("MyConfig");

        var myVal = this.Configuration["MyConfig:ConfigA"];
Run Code Online (Sandbox Code Playgroud)

Mat*_*kan 12

我第一次检查,看看是否有之间的任何变化1.1.12.XJsonConfigurationProvider.cs,最终从您的JSON文件构建检索值的内部代码.这个或任何其他最终被您调用的代码没有变化this.Configuration.GetSection("MyConfig");.

检索值的方法是,Configuration将按照代码中定义的相反顺序MyConfig在每个配置提供程序查找您的密钥,直到找到值.在您的示例中,提供者(json,envionment变量,命令行参数)在Webhost.CreateDefaultBuilder() (见此处)中提供.

查看JsonConfigurationFileParser.cs的代码,它构建了一个Dictionary<string, string>for键和值,但仅用于原始值.也就是说,没有键被存储用于MyConfig(在这一级它是一个对象),但将有一个键MyConfig:ConfigA和阵列值将看起来像MyConfig:ConfigA:0,MyConfig:ConfigA:1等等.

最后,你会发现,Configuration.GetSection("MyConfig") 总是返回你一个新建成的 ConfigurationSection永远不能为null,而在最糟糕的将有Value 属性null.

那么当你将鼠标悬停在ConfigurationSection智能感知器上并查看Value属性时会发生的情况是,每个配置提供程序都已被搜索,并且没有一个被发现有一个"MyConfig"键,其原始值转换为字符串返回.

你至少需要打电话:

services.Configure<MyConfigOptions>(configuration.GetSection("MyConfig"));
services.AddSingleton(cfg => cfg.GetService<IOptions<MyConfigOptions>>().Value);
Run Code Online (Sandbox Code Playgroud)

将它作为C#对象注入整个应用程序.否则,使用冒号["MyConfig:ConfigA"]分隔符语法或使用,调用单个值var mySection = this.Configuration.GetSection("MyConfig")["ConfigA"];,这是多余的,但说明它仅用于检索基元.

要绑定到C#对象并注入它们,我创建了以下扩展方法:

public static class IServiceCollectionExtensions
{
    public static IServiceCollection AddConfigOptions<TOptions>(this IServiceCollection services,
        IConfiguration configuration, string section) where TOptions : class, new()
    {
        services.Configure<TOptions>(configuration.GetSection(section));
        services.AddSingleton(cfg => cfg.GetService<IOptions<TOptions>>().Value);
        return services;
    }
}
Run Code Online (Sandbox Code Playgroud)

可以像这样调用:

public class Startup
{
    public Startup(IConfiguration configuration) => Configuration = configuration;

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddConfigOptions<EmailOptions>(Configuration, "Email")
Run Code Online (Sandbox Code Playgroud)

并注入如下:

public class EmailSender : IEmailSender
{
    private EmailOptions _emailOptions;

    public EmailSender(EmailOptions options) => _emailOptions = options;
Run Code Online (Sandbox Code Playgroud)

  • 从MS文档中可以看出这一点并不明确. (4认同)
  • 那是因为这违背了微软的说法.您应该将IOptions注入到类中,而不是尝试注入配置实例. (2认同)