NET core configuration array with Bind

New configuration system of.NET core is really nice, but it does not works very well with arrays, I have a configuration object that has an array of FirewallRules

1
        public FirewallRule[] Rules { get; set; }

This rule is simply composed by four simple properties.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class FirewallRule
{
    internal FirewallRule()
    {
    }

    public FirewallRule(string name, int udpPort, int tcpPort, string secret)
    {
        Name = name;
        UdpPort = udpPort;
        TcpPort = tcpPort;
        Secret = secret;
    }

    public String Name { get; set; }

    public Int32 UdpPort { get; set; }

    public Int32 TcpPort { get; set; }

    public String Secret { get; set; }
}

Ok, nothing complex, now I’m expecting to being able to write this json configuration file to configure a single rule.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{
  "Rules" : [
    {
      "Name": "Rdp",
      "UdpPort": 23456,
      "TcpPort": 3389,
      "Secret": "this_is_a_secret"
    }
 ]
}

And being able to configure using standard Bind utilities of.NET configuration extensions.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
            const string testValue = @"
{
  ""Rules"" : [
    {
      ""Name"": ""Rdp"",
      ""UdpPort"": 23456,
      ""TcpPort"": 3389,
      ""Secret"": ""this_is_a_secret""
    }
 ]
}";
            using var ms = new MemoryStream(Encoding.UTF8.GetBytes(testValue));
            IConfiguration configuration = new ConfigurationBuilder()
               .SetBasePath(AppDomain.CurrentDomain.BaseDirectory)
               .AddJsonStream(ms)
               .Build();

            var config = new Configuration();
            configuration.Bind(config);

Now I’m disappointed because the test fails because in Rules array I have only a single null element. It seems that Bind does not work perfectly with arrays or am I doing something wrong.

The solution was quite simple, I created a method inside the Configuration object that will allows binding from a standard.NET Core IConfiguration object

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
public void Bind(IConfiguration configuration)
{
    configuration.Bind(this);

    List<FirewallRule> rulesList = new List<FirewallRule>();
    var rules = configuration.GetSection("Rules").GetChildren().ToList();
    foreach (var rule in rules)
    {
        var firewallRule = new FirewallRule();
        rule.Bind(firewallRule);
        rulesList.Add(firewallRule);
    }

    Rules = rulesList.ToArray();
}

As you can see I explicitly get the section Rules, and for each child I explicitly created a FirewallRule and populate properties with standard Bind() method. And everything worked perfectly. I’am a little bit puzzled, because I suspect that I’m doing something wrong because base Bind() method should work out of the box, but at least with this fix all tests are still green.

Gian Maria.