为何Configuration.Bind无法为静态类的集合属性赋值,但Get方法可正常工作?
为何Configuration.Bind无法为静态类的集合属性赋值,但Get方法可正常工作?
这个问题其实是因为Bind和Get方法的核心工作逻辑完全不同,结合你代码里的集合类型细节,就导致了这样的差异:
先搞懂两者的本质区别
Bind是“修改现有对象”:它不会给你创建新对象,只会拿着你传入的现有对象,尝试把配置里的值填充进去。对于集合来说,它需要往你提供的现有集合里添加元素,但前提是这个集合支持修改(比如有Add方法)。Get<T>是“创建新对象并返回”:它直接从配置节反序列化出一个全新的T类型对象,你拿到这个新对象后赋值给属性,相当于直接替换掉原来的空集合,自然能拿到配置里的内容。
你的代码为什么会失败?
看你的ExternalApiSettings.Users:
public static class ExternalApiSettings { public static IEnumerable<ExternalApiUser> Users { get; set; } = Array.Empty<ExternalApiUser>(); }
初始值是Array.Empty<ExternalApiUser>(),这是一个固定长度的空数组,而且IEnumerable<T>本身只是一个枚举接口,根本没有Add方法。当你调用Bind(ExternalApiSettings.Users)时,Bind拿到这个空数组,想往里面加元素却无从下手,最后只能保持数组为空。
而用Get方法时,它会自动创建一个支持修改的集合(比如List<ExternalApiUser>),把配置里的元素塞进去,再赋值给Users,直接替换掉原来的空数组,所以能正常工作。
为什么另一个Bind操作能成功?
你提到SiteSettings.ErrorPageCollection的Bind是正常的,结合你给出的代码,大概率是以下情况之一:
- 你在Bind之前,已经把
ErrorPageCollection改成了可修改的集合(比如List<ErrorPageSettings>),而不是初始的空数组; - Umbraco的配置绑定逻辑做了特殊处理,自动把
IEnumerable<T>类型的目标转换成了可修改的集合; - 可能你实际调用的是绑定到整个
SiteSettings类(比如Bind(SiteSettings)),而不是直接绑定到ErrorPageCollection的当前值——这种情况下,框架会找到ErrorPageCollection属性,直接把反序列化后的新集合赋值给它,效果和Get方法一样。
解决办法
如果你想继续用Bind让Users正常加载配置,有两个简单的方案:
方案1:把集合改成可修改类型
把Users的类型换成List<ExternalApiUser>,初始值设为新的空列表,这样Bind就能往里面加元素了:
public static class ExternalApiSettings { public static List<ExternalApiUser> Users { get; set; } = new List<ExternalApiUser>(); }
然后正常调用Bind:
builder.Configuration.GetSection("ExternalApiSettings").Bind(ExternalApiSettings.Users);
方案2:绑定到整个静态类
调整你的配置结构(或者绑定路径),让配置节对应整个ExternalApiSettings类,然后绑定到类本身:
修改配置为:
"ExternalApiSettings": { "Users": [ { "User": "Administrator", "Key": "From user secrets", "Roles": ["Admin"], "Controllers": ["All"] } ] }
然后调用绑定:
builder.Configuration.GetSection("ExternalApiSettings").Bind(typeof(ExternalApiSettings));
这样框架会自动找到Users属性,把反序列化后的集合赋值给它,和Get方法的效果一致。
备注:内容来源于stack exchange,提问作者Pete
相关产品推荐
相关产品推荐

