.NET Core configuration manager, reading a dictionary where one key has a colon inside, gives an odd error message about the value, is this expected?
Asked Answered
A

1

5

The following program:

using System;
using System.Collections.Generic;
using Microsoft.Extensions.Configuration;

namespace ConsoleApp3
{
    class Program
    {
        static void Main()
        {
            var builder = new ConfigurationBuilder();
            builder.AddJsonFile("appsettings.json");

            var configuration = builder.Build();
            var options = configuration.Get<Options>();
            foreach (var kvp in options.Values)
                Console.WriteLine($"{kvp.Key}: {kvp.Value}");
        }
    }

    internal class Options
    {
        public Dictionary<string, bool> Values { get; } = new Dictionary<string, bool>();
    }
}

When given this appsettings.json file, runs perfectly:

{
    "Values": {
        "a": true,
        "b": false
    }
}

but change the appsettings.json contents to this:

{
    "Values": {
        "a:b": true,
        "b": false
    }
}

and I get this exception:

Unhandled Exception: System.InvalidOperationException: Cannot create instance of type 'System.Boolean' because it is missing a public parameterless constructor.

stack trace:

   at Microsoft.Extensions.Configuration.ConfigurationBinder.CreateInstance(Type type)
   at Microsoft.Extensions.Configuration.ConfigurationBinder.BindInstance(Type type, Object instance, IConfiguration config, BinderOptions options)
   at Microsoft.Extensions.Configuration.ConfigurationBinder.BindDictionary(Object dictionary, Type dictionaryType, IConfiguration config, BinderOptions options)
   at Microsoft.Extensions.Configuration.ConfigurationBinder.BindInstance(Type type, Object instance, IConfiguration config, BinderOptions options)
   at Microsoft.Extensions.Configuration.ConfigurationBinder.BindProperty(PropertyInfo property, Object instance, IConfiguration config, BinderOptions options)
   at Microsoft.Extensions.Configuration.ConfigurationBinder.BindNonScalar(IConfiguration configuration, Object instance, BinderOptions options)
   at Microsoft.Extensions.Configuration.ConfigurationBinder.BindInstance(Type type, Object instance, IConfiguration config, BinderOptions options)
   at Microsoft.Extensions.Configuration.ConfigurationBinder.Get[T](IConfiguration configuration, Action`1 configureOptions)
   at ConsoleApp3.Program.Main() in D:\Dev\ConsoleApp3\ConsoleApp3\Program.cs:line 15

What am I doing wrong? Note that having a colon in the key is perfectly legal json, but perhaps storing any odd dictionary in the appsettings.json file is not supported?

Apostolic answered 31/8, 2018 at 19:0 Comment(6)
Have you tried escaping the colon? "a\:b"Alcoran
No, let me try thatApostolic
That is invalid json, as \: is not something that needs escaping. Adding two (which thus means I now just added a backslash to the key, in addition to the colon) gets me back to the exception.Apostolic
When the file is read into configuration, unique keys are created to maintain the original hierarchical data structure of the configuration source. The sections and keys are flattened with the use of a colon (:) to maintain the original structure: Your colon is going to break the structure of appsettings file learn.microsoft.com/en-us/aspnet/core/fundamentals/…Contraction
I see, ok, then I will just have to move the paths to a property instead, I was configuring paths and whether they were enabled, guess I cannot use the path as a key then. Thanks. Care to leave it as an answer that I can accept?Apostolic
@LasseVågsætherKarlsen I'm doing a little more reading up on the topic to make sure there are no other ways around it. I'll post something in a bit.Contraction
C
4

Reference Configuration in ASP.NET Core: Hierarchical configuration data

The Configuration API is capable of maintaining hierarchical configuration data by flattening the hierarchical data with the use of a delimiter in the configuration keys.

When the file is read into configuration, unique keys are created to maintain the original hierarchical data structure of the configuration source. The sections and keys are flattened with the use of a colon (:) to maintain the original structure

That means that in the following appsettings.json file

{
    "Values": {
        "a:b": true,
        "b": false
    }
}

The keys would be flattened to

  • Values:a:b
  • Values:b

which is going to break the structure of settings file when the ConfigurationBinder.BindDictionary tries to bind the Dictionary<string, bool> property in the Options

Also referencing this GitHub Issue

Colons are reserved for special meaning in the keys, so they shouldn't be used as part of normal key values.

Contraction answered 31/8, 2018 at 20:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.