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

如何使用Microsoft.Extensions.Configuration读取含Name属性的配置节点

读取含Name属性的XML配置节点问题

问题场景

我在应用中尝试读取内存中的XML配置,配置包含3个节点,但目前只能读取不含Name属性的节点值。

代码实现

XML配置与读取代码

const string content = @"<?xml version=""1.0"" encoding=""utf-8""?>
<configuration>
  <node1 Name=""something"" Foo=""Bar"" />
  <node2 NoName=""something"" Foo=""Bar"" />
  <node3 Name=""ignored"" NoName=""something"" Foo=""Bar"" />
</configuration>";
var doc = new XmlDocument();
doc.LoadXml(content);
using var stream = new MemoryStream();
doc.Save(stream);
stream.Position = 0;
var configurationRoot = new ConfigurationBuilder()
  .AddXmlStream(stream)
  .Build();

var node1 = configurationRoot.GetSection("node1").Get<Node1>();
var node2 = configurationRoot.GetSection("node2").Get<Node2>();
var node3 = configurationRoot.GetSection("node3").Get<Node2>();

对应实体类代码

private class Node1
{
  public string Name { get; set; }
  public string Foo { get; set; }
}

private class Node2
{
  public string NoName { get; set; }
  public string Foo { get; set; }
}

出现的问题

  • node1包含Name属性,用Node1类调用configurationRoot.GetSection("node1").Get<Node1>()无法填充值;
  • node2不含Name属性,用Node2类调用configurationRoot.GetSection("node2").Get<Node2>()可正常填充值;
  • node3包含Name属性,用Node2类调用configurationRoot.GetSection("node3").Get<Node2>()也无法填充任何值。

解决方案

在.NET的XML配置提供器中,Name属性被默认当作节点的名称标识符,而非普通属性。当节点存在Name属性时,配置提供器会将该节点解析为带键的子节点,而非将Name作为属性绑定到实体类。

方案1:修改XML配置的属性名(允许修改配置时优先使用)

将Name属性改为其他名称(比如NodeName),即可正常绑定到实体类的对应属性:

<node1 NodeName="something" Foo="Bar" />

对应的实体类调整为:

private class Node1
{
  public string NodeName { get; set; }
  public string Foo { get; set; }
}

方案2:自定义XML配置提供器的解析逻辑(无法修改配置时使用)

通过自定义XmlConfigurationProvider,重写解析逻辑,忽略Name属性作为节点键的默认行为,将其当作普通属性处理:

public class CustomXmlConfigurationProvider : XmlConfigurationProvider
{
    public CustomXmlConfigurationProvider(XmlConfigurationSource source) : base(source) { }

    protected override void Load(Stream stream)
    {
        var doc = new XmlDocument();
        doc.Load(stream);
        Data = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
        TraverseXmlNodes(doc.DocumentElement, null);
    }

    private void TraverseXmlNodes(XmlNode node, string path)
    {
        if (node.Attributes != null)
        {
            foreach (XmlAttribute attr in node.Attributes)
            {
                // 将Name作为普通属性加入配置,不做特殊处理
                var key = string.IsNullOrEmpty(path) ? $"{node.Name}:{attr.Name}" : $"{path}:{node.Name}:{attr.Name}";
                Data[key] = attr.Value;
            }
        }

        foreach (XmlNode childNode in node.ChildNodes)
        {
            if (childNode.NodeType == XmlNodeType.Element)
            {
                var newPath = string.IsNullOrEmpty(path) ? node.Name : $"{path}:{node.Name}";
                TraverseXmlNodes(childNode, newPath);
            }
        }
    }
}

public class CustomXmlConfigurationSource : XmlConfigurationSource
{
    public override IConfigurationProvider Build(IConfigurationBuilder builder)
    {
        EnsureDefaults(builder);
        return new CustomXmlConfigurationProvider(this);
    }
}

// 使用自定义提供器构建配置
var configurationRoot = new ConfigurationBuilder()
    .Add(new CustomXmlConfigurationSource { Stream = stream })
    .Build();

修改后,实体类就能正常绑定Name属性。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 20:54:16