绑定 .NET Core 无法识别的配置属性

Posted

技术标签:

【中文标题】绑定 .NET Core 无法识别的配置属性【英文标题】:Binding .NET Core Unrecognized configuration properties 【发布时间】:2022-01-15 13:53:42 【问题描述】:

假设我们有以下配置文件


  "TeamRoster:People:0:Name": "Bryan",
  "TeamRoster:People:0:City": "Toronto",
  "TeamRoster:People:0:Interests": "Code",

  "TeamRoster:People:1:Name": "Sebastian",
  "TeamRoster:People:1:City": "Vancouver",
  "TeamRoster:People:1:ApartmentType": "Condo"


以及代表此配置的以下 POCO:

public class TeamRoster

    public Person[] People  get; set; 


public class Person

   public string Name  get; set; 
   public string City  get; set; 

假设我使用 ConfigurationBuilder 来读取 dotnet 核心配置,例如:

IConfiguration config =  
     new ConfigurationBuilder()
           .AddJsonFile("file.json")
           .Build();

var myConfig = config.GetSection("TeamRoster").Get<TeamRoster>();

如何捕获不属于 Person 对象的其他属性(Interests、ApartmentType)?

我的推理超出了上面的琐碎示例。在我的模型中,我可能有几十个附加属性(例如多态类型),我想捕获它们而不必在配置对象中定义它们。理想情况下,我想像[JsonExtendedData] 那样做,但据我所知,即使数据表示为 Json,这只是源。它被读入一个配置对象,然后绑定。

有没有办法自定义 .net 核心绑定?

【问题讨论】:

如果您不知道要创建什么以及有多少,您将如何为其他属性创建一个类。 我想要一个无法识别属性的字典,就像 JsonExtendedData 一样。 好的,你认为这本词典的关键是什么?只是 name ,还是整个字符串? 不确定我明白你在问什么@Serge。基本上,基础配置中未映射到对象属性的任何无法识别的属性都应被视为“无法识别”。所以关键是属性的名称。 【参考方案1】:

为了阐明这一点,Microsoft.Extensions.Configuration 中的IConfigurationRoot 从其底层配置源中抽象出配置数据。开箱即用的配置数据可以来自Json、Azure KeyVault、Command Line、Environment Variables、Xml、Memory、Ini files、User secrets 和individual files(每个文件的密钥) .

这些配置源中的每一个都将其数据加载到字典中,其中层次值使用“:”分隔。当您从 IConfiguration 对象中获取数据时,它会尝试以相反的顺序解析来自每个数据源的值。因此最后添加的配置源具有最高优先级。

IConfiguration 对象到 POCO 对象的映射是使用 ConfigurationBinder 完成的。虽然ConfigurationBinder 确实支持使用TypeConverters 解析值,但这种情况仅有助于映射配置字典中的单个字符串值,而不是整个对象。

ConfigurationBinder 原生支持绑定集合,所以理论上以下两种方法可以用于以下配置。

将固定值与动态值分开

表示数据,使动态数据与静态数据分开。


   "auth": 
      "providers": [
         
            "name": "clientsecret",
            "loginUrl": "https://login.microsoftonline.com/mytenant/oauth2",
            "fields": 
               "client_id": "xxx",
               "client_secret": "yyy"
               "resource": "https://management.azure.com",
               "grant_type": "client_credentials"
            
         ,
         ...
      ]
   

将动态字段绑定到Dictionary&lt;string,string&gt; 时,Binder 将字段映射为键/值对。这种方法的主要优势是我们能够利用 TypeConverters 和固定字段的类型安全性。

public class AuthProvider

    // FIXED FIELDS
    public string Name  get; set; 
    public Uri LoginUrl  get; set; 

    // DYNAMIC FIELDS
    public Dictionary<string,string> Fields  get; set; 

将所有数据映射为动态

稍微有点hackish的方法是将数据中的所有字段描述为兄弟,然后将整个数据绑定为字典。


   "auth": 
     "providers": [
       
         "name": "clientsecret",
         "loginurl": "https://somewhere",
         "client_id": "xxx",
         "client_secret": "yyy",
         "scope": "https://url",
         "grant_type": "client_credentials"
       
     ]
   

我们可以简单地利用直接绑定到字典的优势。请注意,我们使用了 Uri 字段的类型转换器:

public class AuthProvider : Dictionary<string,string>

  public string Name => this["name"]
  public string LoginUrl => this["loginUrl"]

  public Dictionary<string,string> Fields
  
     get 
     
       var propertyNames = GetType().GetProperties().Select(x => x.Name).ToArray();

       var keyPairs = this.Where(kvp => !propertyNames.Contains(kvp.Key));

       return 
          new Dictionary<string,string>(
                keyPairs, 
                StringComparer.OrdinalIgnoreCase);
     
  

【讨论】:

以上是关于绑定 .NET Core 无法识别的配置属性的主要内容,如果未能解决你的问题,请参考以下文章

.NET Core 重定向中无法识别的参数类型 REMOTE_ADDR 和 HTTP_X_FORWARDED_FOR

不同 Windows 上无法识别的属性“multipleSiteBindingsEnabled”问题

分析器错误消息: 无法识别的属性“targetFramework”。

Subsonic 2.2 ASP.NET MVC 无法识别的配置部分

无法识别的属性 requestValidationMode 请注意属性区分大小写 这是怎么回事

BScompilation debug=true targetFramework=4.0 无法识别的属性“targetFramework”