1

I am trying to read a configuration in my application.

Consider the code below...I load an XML in memory and it contains 3 different nodes. I can only get the value of the node with no Name attribute

      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>();

And the Node classes

    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; }
    }

The configuration has 3 nodes, node1 contains the attribute Name and I am trying to read it using Node1

configurationRoot.GetSection("node1").Get<Node1>() does not populate the values.

node2 does not contain the attribute Name and I am trying to read it using Node2

configurationRoot.GetSection("node2").Get<Node2>() populate the values as expected.

Finally, node3 does contain the attribute Name but I am trying to read it using Node2, (that does not care about the name).

configurationRoot.GetSection("node3").Get<Node2>() also does not populate any of the values.

How can I read a node that contains a Name attribute.

FFMG
  • 1,208
  • 1
  • 10
  • 24

1 Answers1

1

The source code on GitHub shows that the Name attribute gets a special treatment.

// The special attribute "Name" only contributes to prefix
// This method retrieves the Name of the element, if the attribute is present

In short, the value of the name attribute is being included in the (section/item) key.

To retrieve node1 you need to call

var node1 = configurationRoot.GetSection("node1:something").Get<Node1>();

For node3 that is

var node3 = configurationRoot.GetSection("node3:ignored").Get<Node2>();

The debug visualizer in Visual Studio for configurationRoot shows these keys.

enter image description here


The documentation explains the concept of this Name attribute and shows some examples about when and how to use.

In .NET 5 and earlier versions, add the name attribute to distinguish repeating elements that use the same element name. In .NET 6 and later versions, the XML configuration provider automatically indexes repeating elements.

pfx
  • 20,323
  • 43
  • 37
  • 57
  • Thanks, that a but inconvenient to be honest, I was hoping there would be a way around it, (via a config flag or a custom builder/provider). I can write my own method to get the value, but it does not feel right. – FFMG Sep 02 '22 at 07:26
  • Well, this is what the out of the box implementation behind `AddXmlStream` does. If that doesn't fit, you'll indeed have to come up with some custom code. You might consider using an alternative for `Name` to bypass that behavior; e.g. `Key` or `Identifier`. – pfx Sep 02 '22 at 08:41