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

我试图从Startup.cs注入配置调用GetSection 。 Value为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() .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"]; 

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

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

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

最后,您会发现Configuration.GetSection("MyConfig") 总是返回一个 永远为null 的新构造的 ConfigurationSection ,最坏的情况是Value 属性null

那么当您将鼠标hover在具有Intellisense的ConfigurationSection上并查看Value属性时会发生的情况是, 每个配置提供程序都已被搜索,并且没有发现任何“MyConfig”键的原始值转换为字符串以返回。

你至少需要打电话:

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

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

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

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

可以像这样调用:

 public class Startup { public Startup(IConfiguration configuration) => Configuration = configuration; public IConfiguration Configuration { get; } public void ConfigureServices(IServiceCollection services) { services.AddConfigOptions(Configuration, "Email") 

并注入如下:

 public class EmailSender : IEmailSender { private EmailOptions _emailOptions; public EmailSender(EmailOptions options) => _emailOptions = options; 

我发现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任务,如下所示:

  

而这似乎完美无缺。

这显然本地开发期间有用。 但是,现在的一般做法是首先不要在文件中进行配置,特别是因为它最终会成为您的回购历史的一部分。 相反,在部署应用程序时,这几天的两种常见做法是使用环境变量来覆盖您的值,甚至更好地使用像consul这样的键/值存储。

此外,我在网上看到了大量关于如何使用services.Configure<>()的奇特示例。配置services.Configure<>()这很好,但Startup.cs已经使用DI为IConfiguration configuration注入值。 这意味着IConfiguration已经在.NET核心的IoC容器中注册,因此这实际上意味着您已经可以在应用程序的任何其他类中使用IConfiguration ,如下所示:

 public JobsRepository(IConfiguration configuration) { this.configA = configuration.GetSection("MyConfig:ConfigA").Value; } 

在我的情况下,我错过了一个包:

Microsoft.Extensions.Configuration.Binder

事实上它在这里被记录为一个微妙的代码注释

配置现在传递到构造函数的启动。 因为它被注入,它可以在Program.cs中提供给你的app 之前预先准备好。

所以你可以尝试使用Program.cs

  public static IWebHost BuildWebHost(string[] args) => WebHost.CreateDefaultBuilder(args) .ConfigureAppConfiguration((context, builder) => { IHostingEnvironment env = context.HostingEnvironment; builder.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true); }) .UseStartup() .Build(); 

希望这可以帮助。

法比安