Configuration.GetSection 方法总是返回 Value 属性为空

113

每次我调用Configuration.GetSection方法时,返回对象的Value属性总是为null。

我的Startup构造函数

public Startup(IHostingEnvironment env)
{
    var builder = new ConfigurationBuilder()
        .SetBasePath(env.ContentRootPath)
        .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
        .AddEnvironmentVariables();

    this.Configuration = builder.Build();
}

我的ConfigureServices方法

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<SqliteSettings>(opts => Configuration.GetSection("SqliteSettings").Bind(opts));

    services.AddOptions();

    services.AddMvc();
}

我的 appsettings.json

{
  "SqliteSettings": {
    "DataSource": "C:\\db.sqlite",
    "NewDatabase": true,
    "Version": 3
  }
}

我使用的类来定义SqliteSettings

public class SqliteSettings
{
    public string DataSource { get; set; }

    public bool? NewDatabase { get; set; }

    public int? Version { get; set; }

    public string Password { get; set; }

    public long? CacheSize { get; set; }

    // More properties
}

我在想JSON可能需要具有相同数量的属性才能匹配,或者可能与数据类型定义有关,但这些可能完全无关。


我认为最好的答案是这个 https://dev59.com/aVgQ5IYBdhLWcg3wWCc0#52273140 - G. Sofien
15个回答

183
根据Microsoft Docs的说明:
当GetSection返回匹配的部分时,Value没有填充。如果该部分存在,则返回Key和Path。
如果您想查看该部分的值,您需要调用GetChildren()方法:Configuration.GetSection("SqliteSettings").GetChildren(); 或者您可以使用:Configuration.GetSection("SqliteSettings").Get<SqliteSettings>()。JSON不需要具有相同数量的属性来匹配。未匹配的空属性将设置为null,未匹配的不可为空属性将设置为它们的默认值(例如:int将被设置为0)。

1
Configuration.GetSection("SqliteSettings").Bind(sqliteSettingsObject); 是另一种读取设置的方式。 - Ram
17
如果你只需要查看该部分是否存在,可以使用Exists()方法,例如: Configuration.GetSection("SqliteSettings").Exists() - ColinM
2
".Get<>()" 版本对我来说运行良好。令人沮丧的是,MSDN 只显示了一个 As 转换的用法,我敢打赌这让很多人感到困惑。 - Dan
2
我一直得到一个对象的实例,但所有属性都为空。原来是我定义了没有 setter 的属性(即 public string MyString { get; }),这不允许 .NET 映射到我的对象。 - user1024742
要使用.Get<SqliteSettings>(),您需要将Microsoft.Extensions.Configuration.Binder NuGet包添加到您的项目中。 - Mohammad Taherian
显示剩余2条评论

50
  1. 右键点击appsettings.json,选择属性。
  2. 选择复制到输出目录 = 始终复制。

6
浪费太多时间在一件如此简单的事情上了......谢谢。 - Mike M
一样!copyifnever 太令人困惑了。文件只会被复制一次,你添加的新设置将无法通过。最后,似乎有些设置会生效,有些则不会! - DavidY
这是确切的答案,谢谢你,你是个救星。 - Samithra niroshana
哦,我的天啊,太感谢了!这真是太不直观了。 - undefined

21

只需修改您的 ConfigureServices 方法如下:

public void ConfigureServices(IServiceCollection services)
{
    services.AddOptions();

    services.Configure<SqliteSettings>(Configuration.GetSection("SqliteSettings"));

    services.AddMvc();
}

并且它应该能够工作。


13
很遗憾,虽然订单下单可能会解决将来可能出现的错误,但它并没有起作用。 Configuration.GetSection 仍然返回 .Value 为空。 - Liam Mueller
你可以分享一下你是如何调用 .Value 的吗? - Ali
3
为了查看是否获取到了JSON,我只需执行var x = Configuration.GetSection("SqliteSettings");,然后在Visual Studio中检查x,特别是Value - Liam Mueller
4
如果您想直接从“Configuration”中读取,请使用类似于“Configuration [“SqliteSettings:DataSource”]”这样的语法。如果您想在控制器中使用它,请使用options pattern - Ali
1
我了解到在Startup.cs中,你只能获取配置JSON的“叶子”,而不像在.NET Core 1或之前版本中那样。可以使用以下代码:services_.Configure<CorporateConfiguration>( options_ => { options_.Name = Configuration.GetValue<string>("Corporate:Name"); options_.BrandLogo = Configuration.GetValue<string>("Corporate:BrandLogo"); }); - barbara.post
@LiamMueller,据我所知 - Configuration.GetSection("SqliteSettings") 的 Value 属性为空,因为该属性是字符串类型(请参见 IConfigurationSection 接口)。SqliteSettings 不是一个普通的 JSON 字符串,而是一个对象。因此,您可以调用 Configuration.GetSection("SqliteSettings").Get<SqliteSettings>() 来获取该部分的值。 - Roman Bats

12
如果其他答案都不能解决问题,那么另一个原因可能是Options类的属性是私有的(或者没有可访问的setter)。

1
非常感谢。显然,“internal”对于这个目的来说不够可访问。 - Nae
非常感谢,我只定义了设置类属性的getter。 - Krzysztofz01

8

我的问题是,.bind() 方法的对象实例没有被初始化。

services.Configure<SqliteSettings>(opts => Configuration.GetSection("SqliteSettings").Bind(opts));

在调用 .bind(opts) 之前,我先初始化了该值:

SqlliteSettings opts = new SqliteSettings();

绑定本地设置变量:
Configuration.GetSection(AppSettingsSectionName).Bind(opts);

并且单独进行了容器注册:

services.Configure<AppSettings>(Configuration.GetSection("SqlliteSettings"));

这解决了问题,因为当提供的实例为空时,.Bind()方法将返回null。

2
哇塞,你真是个英雄,微软太蠢了。如果你要设置一个值,为什么不初始化呢? - Red
初始化绑定目标!您拯救了我的一天,先生! - Lionet Chen

5

这个方法适用于控制台应用程序:

var connectionString = config["ConnectionStrings:DefaultConnection"]

4

确保您的配置对象具有属性访问器,否则它将无法正确绑定。知道这一点可以为我今天节省2个小时。

public class MyConfiguration
{
        public string ConfigurationOption1; // BAD
        public string ConfigurationOption2 { get; set; } // GOOD
}

1
是的,没错!我们必须记得配置全部为公开。 - Payedimaunt
糟糕!这是我的问题,我将其标记为内部。谢谢! - Trey Mack

2
在我的情况下,我正在使用VS Code和.net core 3.x webapp。我遇到了类似的问题,GetSection()或Configuraton["Section:KeyName"]返回null,我检查了GetSection().Exists()也返回false。因此,我尝试在ConfigureServices中添加configbuilder来解决这个问题。
  public void ConfigureServices(IServiceCollection services)
  {
      //Initialize the builder 
      var builder = new ConfigurationBuilder()
                    .SetBasePath(Environment.CurrentDirectory)
                    .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
                    .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json", optional: true)//To specify environment
                    .AddEnvironmentVariables();//You can add if you need to read environment variables.

      //Build the configuration
      IConfiguration Configuration = builder.Build();

       
      services.Configure<SqliteSettings>(Configuration.GetSection("SqliteSettings"));
      //Similar to below 
      //services.Configure<EntityClass>(Configuration.GetSection("EntityConfigSection"));
      
  }

注意:请确保.VScode/launch.json文件中的cwd和program值正确。 代码从cwd值中选择当前工作目录,因此我们需要确保它设置正确。
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "X.X.X",
"configurations": [
    {
        "name": ".NET Core Launch (web)",
        "type": "coreclr",
        "request": "launch",
        "preLaunchTask": "build",
        "program": "${workspaceFolder}/<ProjectLocation>/bin/<BuildType>/<Version>/<ProjectDll>",
        "args": [],
        "cwd": "${workspaceFolder}/<ProjectLocation>",
        "stopAtEntry": false,
        "serverReadyAction": {
            "action": "openExternally",
            "pattern": "\\bNow listening on:\\s+(https?://\\S+)"
        },
        "env": {
            "ASPNETCORE_ENVIRONMENT": "Development"
        },
        "sourceFileMap": {
            "/Views": "${workspaceFolder}/Views"
        }
    }

]}

1
此答案中的配置片段非常有用,因为如果找不到appsettings.json,它会抛出错误。这帮助我追踪到我的问题,也就是在launch.json中,cwd值设置为错误的文件夹,这是非常棘手的问题,因为除了配置之外,其他所有都正常工作。谢谢! - Daniel Veihelmann

2
var serviceProvider = services.BuildServiceProvider();

必须在所有services.Configure调用之后进行。


你永远不应该手动构建服务提供者。 - JCode

1
如果你的依赖注入失败,并且在调试后得出结论认为这个方法是问题所在,那么它并不是!
这已足够进行注册:
services.Configure<SqliteSettings>(Configuration.GetSection("SqliteSettings"));

你需要在IOptions接口中注入你的配置类,这将解决依赖注入问题。我浪费了几个小时来解决这个问题,希望能帮助其他人。

你是怎么做到的? - Edu Cielo
1
@EduCielo 注入了 IOptions<SqliteSettings>。 - Ufuk Hacıoğulları

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接