ASP.net Core 2.0 Preview配置中的appsettings.json获取null [英] appsettings.json in ASP.net Core 2.0 Preview configuration GetSection null

查看:275
本文介绍了ASP.net Core 2.0 Preview配置中的appsettings.json获取null的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图从Startup.cs中的注入配置中调用GetSection. 值是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();

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"];

解决方案

我首先检查一下最终调用的其他任何代码都没有任何更改.

检索值的工作方式是Configuration将按照代码中的定义以相反的顺序在每个配置提供程序 中寻找密钥MyConfig,直到找到一个值为止.在您的示例中,在Webhost.CreateDefaultBuilder() JsonConfigurationFileParser.cs ,它为键和值(,但仅对于原始值)构建了Dictionary<string, string> .也就是说,没有存储MyConfig的键(在这个级别上它是一个对象),但是会有MyConfig:ConfigA的键,并且数组值看起来像MyConfig:ConfigA:0MyConfig:ConfigA:1等.

最后,您会发现Configuration.GetSection("MyConfig")

您至少需要致电:

services.Configure<MyConfigOptions>(configuration.GetSection("MyConfig"));
services.AddSingleton(cfg => cfg.GetService<IOptions<MyConfigOptions>>().Value);

将其作为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;
    }
}

可以这样称呼:

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

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddConfigOptions<EmailOptions>(Configuration, "Email")

并像这样注入:

public class EmailSender : IEmailSender
{
    private EmailOptions _emailOptions;

    public EmailSender(EmailOptions options) => _emailOptions = options;

I was trying to call GetSection from injected configuration in the Startup.cs. The Value was null, while indexer to a concrete section value returns non-null value. It seems to me a bug behind the GetSection method or I am wrong with it?

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();

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"];

解决方案

I first checked to see if there were any changes between 1.1.1 and 2.x of JsonConfigurationProvider.cs, the internal code that ultimately constructs retrievable values from your JSON file. There were no changes to this or any of the other code that ultimately gets called by your this.Configuration.GetSection("MyConfig");.

The way retrieving values works is that the Configuration will look for your key MyConfig in each config provider in reverse order as defined in code until a value is found. In your example, providers (json, envionment variables, command line args) are provided within Webhost.CreateDefaultBuilder() (see here).

Looking at the code for JsonConfigurationFileParser.cs, it builds a Dictionary<string, string> for keys and values, but only for primitive values. That is, no key is stored for MyConfig (at this level it is an object), but there will be a key for MyConfig:ConfigA, and array values would look like MyConfig:ConfigA:0, MyConfig:ConfigA:1, etc.

Lastly, you will find that Configuration.GetSection("MyConfig") always returns you a newly constructed ConfigurationSection that is never null, and at the very worst will have a Value property of null.

So what happens when you hover over a ConfigurationSection with Intellisense and look at the Value property is that every config provider had been searched and none was found to have a key of "MyConfig" with a primitive value converted to string to return.

You will at the very least need to call:

services.Configure<MyConfigOptions>(configuration.GetSection("MyConfig"));
services.AddSingleton(cfg => cfg.GetService<IOptions<MyConfigOptions>>().Value);

to have it injected throughout your app as a C# object. Otherwise, call individual values with the colon ["MyConfig:ConfigA"] separator syntax or with var mySection = this.Configuration.GetSection("MyConfig")["ConfigA"];, which is redundant but illustrates it is only used to retrieve primitives.

To bind to C# objects and inject them, I created the following extension method:

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;
    }
}

which can be called like this:

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

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddConfigOptions<EmailOptions>(Configuration, "Email")

and injected like this:

public class EmailSender : IEmailSender
{
    private EmailOptions _emailOptions;

    public EmailSender(EmailOptions options) => _emailOptions = options;

这篇关于ASP.net Core 2.0 Preview配置中的appsettings.json获取null的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆