You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Configuration GetRequiredSection()读取嵌套配置对象树?

在.NET Core中读取带嵌套属性的配置节问题解决

问题重现

我的配置片段:

{
  "SMTP":
  {
    "Name": "...",
    "UserName": "...",
    "Password": "...",
    "HostName": "...",
    "Port": "587",
    "Security": "STARTTLS",
    "OAuth2":
    {
      "ClientId": "",
      "ClientSecret": "",
      "Scopes":
      [
      ]
    }
  }
}

用以下record类型读取配置:

public record OAuth2Credentials(string ClientId, string ClientSecret, string[] Scopes);

public record SmtpConfiguration(string Name, string UserName, string Password, string HostName, int Port, string Security, OAuth2Credentials OAuth2);

执行读取代码时:

SmtpConfiguration smtpConfig =
   Program.Configuration!
  .GetRequiredSection("SMTP")
  .Get<SmtpConfiguration>()!;

抛出错误:

System.InvalidOperationException: Cannot create instance of type
'WebApi.SendEMail.SmtpConfiguration' because parameter 'OAuth2' has
no matching config. Each parameter in the constructor that does not
have a default value must have a corresponding config entry.

请问如何用Configuration.GetRequiredSection()读取嵌套的对象树?


错误原因

问题出在位置参数式的record构造逻辑:.NET配置绑定器需要严格匹配构造函数的每一个必填参数,而你的OAuth2Credentials要求必须传入Scopes数组,配置里的空数组无法被自动映射到构造参数;同时OAuth2节点内的空字符串值也导致绑定器无法成功构造OAuth2Credentials实例,最终外层的SmtpConfiguration初始化失败。

解决方案

方案1:给Record构造参数添加默认值(最简洁)

修改record定义,给可选参数加上默认值,让绑定器在配置值为空时能使用默认值构造实例:

public record OAuth2Credentials(
    string ClientId = "", 
    string ClientSecret = "", 
    string[] Scopes = default!);

public record SmtpConfiguration(
    string Name, 
    string UserName, 
    string Password, 
    string HostName, 
    int Port, 
    string Security, 
    OAuth2Credentials OAuth2 = default!);

此时原来的读取代码可以直接正常运行,无需修改。

方案2:使用带属性的Record(替代位置参数)

把record改成属性初始化的形式,让绑定器通过属性赋值而非构造函数填充数据:

public record OAuth2Credentials
{
    public string ClientId { get; init; } = "";
    public string ClientSecret { get; init; } = "";
    public string[] Scopes { get; init; } = Array.Empty<string>();
}

public record SmtpConfiguration
{
    public string Name { get; init; } = "";
    public string UserName { get; init; } = "";
    public string Password { get; init; } = "";
    public string HostName { get; init; } = "";
    public int Port { get; init; }
    public string Security { get; init; } = "";
    public OAuth2Credentials OAuth2 { get; init; } = new();
}

这种方式更灵活,即使配置节点为空,也能通过默认值初始化对象。

方案3:你选定的分步绑定方案

你实现的分步绑定确实能保证类型安全,缺点是代码相对繁琐,但可以精准控制每个节点的绑定逻辑:

using System;

public record OAuth2Credentials(string ClientId, string ClientSecret)
{
  public string[] Scopes = Array.Empty<string>();
}

public record SmtpConfiguration(string Name, string UserName, string Password, string HostName, int Port, string Security)
{
  public OAuth2Credentials OAuth2 = new OAuth2Credentials("", "");
}

try
{
  var smtpConfig = Program.Configuration!.GetRequiredSection("SMTP").Get<SmtpConfiguration>()!;
  smtpConfig.OAuth2 = Program.Configuration!.GetRequiredSection("SMTP:OAuth2").Get<OAuth2Credentials>()!;
  smtpConfig.OAuth2.Scopes = Program.Configuration!.GetRequiredSection("SMTP:OAuth2:Scopes").Get<string[]>()!;
}
catch (InvalidOperationException ex) 
{ 
    return TypedResults.BadRequest($"Invalid SMTP configuration: {ex.Message}"); 
}

适合需要对每个节点绑定做额外校验的场景。

内容的提问来源于stack exchange,提问作者AxD

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 18:52:43