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

Posted

技术标签:

【中文标题】ASP.net Core 2.0 Preview 配置中的 appsettings.json GetSection null【英文标题】:appsettings.json in ASP.net Core 2.0 Preview configuration GetSection null 【发布时间】:2017-12-15 06:29:21 【问题描述】:

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

appsettings.json:

“我的配置”: “配置A”:“值A”, “配置B”:“值B”

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

【问题讨论】:

【参考方案1】:

我首先检查了JsonConfigurationProvider.cs 的1.1.1 和2.x 之间是否有任何变化,这是最终从您的JSON 文件构造可检索值的内部代码。您的this.Configuration.GetSection("MyConfig"); 最终调用的此代码或任何其他代码都没有更改。

检索值的工作方式是Configuration 将在每个配置提供程序中按代码中定义的相反顺序 查找您的密钥MyConfig,直到找到一个值。在您的示例中,Webhost.CreateDefaultBuilder()(see here) 中提供了提供程序(json、环境变量、命令行参数)。

查看JsonConfigurationFileParser.cs 的代码,它为键和值构建了一个Dictionary&lt;string, string&gt;但仅用于原始值。也就是说,没有为MyConfig 存储键(在此级别它是一个对象),但将有一个用于MyConfig:ConfigA 的键,并且数组值看起来像MyConfig:ConfigA:0MyConfig:ConfigA:1 等。

最后,你会发现Configuration.GetSection("MyConfig")always returns you a newly constructedConfigurationSection永远不会为空,最坏的情况是Value属性 null.

那么,当您使用 Intellisense 将鼠标悬停在 ConfigurationSection 上并查看 Value 属性时会发生什么情况,即 每个 配置提供程序都已被搜索,但没有找到具有“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;

【讨论】:

这行得通,而且从 MS 文档中看不出来。 那是因为这违背了微软的承诺。您应该将 IOptions 注入到您的类中,而不是尝试注入您的配置实例。【参考方案2】:

就我而言,我错过了一个包裹:

Microsoft.Extensions.Configuration.Binder

事实上,它在here 中被记录为一个微妙的代码注释

【讨论】:

【参考方案3】:

我发现 AspNetCore 2.0 在配置方面比 1.x 简单得多。

如果您在 Startup(IConfiguration configuration) 构造函数中放置断点,您会注意到 configuration 变量有大约 5 个提供者。

JsonConfigurationProvider 是您对 appsettings.json 文件感兴趣的提供程序,但您可能会注意到Data 属性有一个Count=0。这很可能是因为您的应用程序正在JsonConfigurationProvider.Source.FileProvider.Root(默认为 wwwroot)中指定的目录中查找 appsettings.json 文件。

我所做的只是在 .csproj 文件中添加一个 MSBuild 任务,如下所示:

<Copy SourceFiles="appsettings.json" DestinationFolder="wwwroot" />

这似乎很有效。

这在仅限本地开发期间显然很有用。然而,现在的一般做法是从一开始就永远不要在文件中进行配置,特别是因为它最终会成为你的回购历史的一部分。相反,在部署您的应用程序时,目前两种常见做法是使用环境变量来覆盖您的值,或者使用 consul 之类的键/值存储更好。

此外,我在网上看到一大堆关于如何使用services.Configure&lt;&gt;() 的精美示例,这很好,但Startup.cs 已经使用DI 将值注入IConfiguration configuration。这意味着 IConfiguration 已经在 .NET core 的 IoC 容器中注册,因此这实质上意味着您已经可以在应用程序的任何其他类中使用 IConfiguration,如下所示:

public JobsRepository(IConfiguration configuration)

    this.configA = configuration.GetSection("MyConfig:ConfigA").Value;

【讨论】:

您永远不想将 appsettings.json 复制到 wwwroot。如果您这样做,您将公开(可查看)它。你为什么要这样公开你的配置? 在启动期间,它会在您的 WebRoot 中查找 appSettings.json。这在仅在本地开发 期间显然很有用。然而,现在的一般做法是从一开始就永远不要在文件中进行配置,特别是因为它最终会成为你的回购历史的一部分。相反,在部署您的应用程序时,如今两种常见做法是使用环境变量来覆盖您的值,或者甚至更好地使用像 consul 这样的键/值存储......如果没有先澄清就没有必要投反对票。 即使是本地开发,也不应该去那里。该文件属于其他二进制文件旁边的 /bin 编译输出目录。 Aspnetcore 将从那里加载它。

以上是关于ASP.net Core 2.0 Preview 配置中的 appsettings.json GetSection null的主要内容,如果未能解决你的问题,请参考以下文章

.NET 6 Preview 5 中的 ASP.NET Core 更新

.NET Core 3.0 Preview 6中对ASP.NET Core和Blazor的更新

Asp.Net Core 7 preview 4 重磅新特性--限流中间件

.NET 6 Preview 4 已发布,ASP.NET Core 更新内容

从ASP.NET Core 3.0 preview 特性,了解CLR的Garbage Collection

.NET 6 Preview 6 现已推出,其中包括对 ASP.NET Core 的许多重大改进。