0

How can I read an array of configuration values using Microsoft.Extensions.Configuration with binding?

For example, given the following XML configuration:

<root>
    <eventConfiguration>
        <event name="0" source="" type="" target="" />
        <event name="1" source="" type="" target="" />
        <event name="2" source="" type="" target="" />
    </eventConfiguration>
</root>

And the following classes:

public class Configuration
{
    public EventConfiguration EventConfiguration {get; set;}
}

public class EventConfiguration
{
    public List<Event> Events {get; set;}
}

public class Event
{
    public string Name {get; set;}
    public string Source {get; set;}
    public string Type {get; set;}
    public string Target {get; set;}
}

When I try to get an instance of Configuration the Event-List is null:

IConfigurationBuilder builder = new ConfigurationBuilder();
builder.AddXmlFile("default.xml");
var root = builder.Build();
    
// with binding
var configuration = root.Get<Configuration>();
var events = configuration.EventConfiguration.Events; // null

// without binding
var eventSource = root.GetValue("eventConfiguration:event:0:source", default(string)); // not null
Gabor
  • 3,021
  • 1
  • 11
  • 20
MiGro
  • 471
  • 1
  • 4
  • 17

1 Answers1

1

The solution is to add ConfigurationKeyNameAttribute to the Events property as your XML element's name is event not events.

public class EventConfiguration
{
    [ConfigurationKeyName(nameof(Event))]
    public List<Event> Events { get; set; }
}

Update #1:

This is my code that works.

ConsoleApp1.csproj

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp3.1</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="6.0.0" />
    <PackageReference Include="Microsoft.Extensions.Configuration.Xml" Version="6.0.0" />
  </ItemGroup>

  <ItemGroup>
    <None Update="default.xml">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
  </ItemGroup>

</Project>

default.xml

<?xml version="1.0" encoding="utf-8" ?>
<root>
  <eventConfiguration>
    <event name="0" source="" type="" target="" />
    <event name="1" source="" type="" target="" />
    <event name="2" source="" type="" target="" />
  </eventConfiguration>
</root>

Program.cs

using Microsoft.Extensions.Configuration;

using System;
using System.Collections.Generic;

namespace ConsoleApp1
{
    internal class Program
    {
        static void Main(string[] args)
        {
            IConfigurationBuilder builder = new ConfigurationBuilder();
            builder.AddXmlFile("default.xml");
            var configurationRoot = builder.Build();

            // with binding
            var configuration = configurationRoot.Get<Configuration>();
            var events = configuration.EventConfiguration.Events;

            Console.WriteLine($"events.Count = [{events?.Count}]");

            for (int i = 0; i < (events?.Count ?? 0); i++)
            {
                Console.WriteLine(events[i]);
            }

            // without binding
            var eventSource = configurationRoot.GetValue("eventConfiguration:event:0:source", default(string));
        }
    }

    public class Configuration
    {
        public EventConfiguration EventConfiguration { get; set; }
    }

    public class EventConfiguration
    {
        [ConfigurationKeyName(nameof(Event))]
        public List<Event> Events { get; set; }
    }

    public class Event
    {
        public string Name { get; set; }
        public string Source { get; set; }
        public string Type { get; set; }
        public string Target { get; set; }

        public override string ToString()
        {
            return $"Event: Name=[{Name}]";
        }
    }
}

The output is:

events.Count = [3]
Event: Name=[0]
Event: Name=[1]
Event: Name=[2]

P:\Projects\ConsoleApp1\ConsoleApp1\bin\Debug\netcoreapp3.1\ConsoleApp1.exe (process 15136) exited with code 0.
Press any key to close this window . . .
Gabor
  • 3,021
  • 1
  • 11
  • 20
  • After adding ```ConfigurationKeyNameAttribute``` the List is still null. – MiGro Mar 25 '22 at 08:50
  • @MiGro, did you set the attribute value to `Event` or `Events`? When I tried then the list had all the 3 events from the XML file. – Gabor Mar 27 '22 at 22:47
  • I added it to ```public List Events {get;set;}``` property. – MiGro Mar 28 '22 at 07:30
  • @MiGro, I updated my answer with the code I have tested and it works. Can you try it? Btw. my previous question was that to the `Events` property you applied `[ConfigurationKeyName(nameof(Event))]` or `[ConfigurationKeyName(nameof(Events))]`? – Gabor Mar 28 '22 at 22:43
  • I tested in a new project with .NET Framework and .NET 6 and it worked. It did not work in my other solution, because I the package versions of the ```Microsoft.Extensions.Configuration``` packages had to be updated to 6.x. Thank you very much. – MiGro Mar 29 '22 at 10:41