2

I have a class with one List<string> variable having default values.

public class MyOptions{
    public List<string> Settings {get; set;} = new List<string>(){"Controls","Menus"};
}

Then I register it in ConfigureServices method like

services.Configure<MyOptions>(Configuration.GetSection("MyOptions"));

I want to be able to change the value of Settings collection without changing the code. In my appsettings.json, I have tried the following

{
    "MyOptions":{
        "Settings:0":"ReplacedSettings"
    }
}

to replace "Controls" with "ReplacedSettings", but it doesn't work and I now get Settings with three values instead ["Controls","Menus","ReplacedSettings"] whereas I want ["ReplacedSettings","Menus"].

Is this supported? Or is there any similar data structure I can with Option pattern that allows defaults values to be overridden from appsettings.json.

Thanks.

1 Answer 1

6

This behavior is by design because when binding to collections in options, the values will be appended. The reason why you cannot overwrite the default values from your MyOptions options model is that options and configuration are actually two distinct concepts which can work together but don’t have to. I go into more detail in an answer to a related question but basically handling the configuration and binding the configuration to options objects are two separate things.

When you just look at your configuration, then there’s the following value:

MyOptions:Settings:0 => "ReplacedSettings"

The configuration system does not know about your "Controls" and "Menus" values. Those only exist in the options type you later bind to. So because there is nothing else in the configuration, there is nothing you can replace here. And when the binder then uses the configuration to set up the options types, it will just append that single value "ReplacedSettings" to the list.

If you want to make sure that you can replace values, then you will have to declare those settings in configuration:

MyOptions:Settings:0 => "Controls"
MyOptions:Settings:1 => "Menus"

If you now apply the configurations with your "ReplacedSettings", then it will properly replace the one matching key and leave the other:

MyOptions:Settings:0 => "ReplacedSettings"
MyOptions:Settings:1 => "Menus"

The common solution for this is to use the appsettings.json for default values. That way, you can overwrite those with an environment-specific appsettings.<env>.json or some other source (e.g. environment variables) and apply your overrides. Of course, you shouldn’t specify the defaults in your options type then.

Sign up to request clarification or add additional context in comments.

2 Comments

Do you know if there is any workaround for this? It seems as they closed the issue with a very unideal explaination ("it is as it is and it would be a breaking change to adjust the behavior").
@thomasgalliker Workaround for which part exactly? If you want to values to be replaceable, you will have to specify the default in configuration as well. If you want settings not to replace each other, you could work with additional collections (e.g. AdditionalSettings) that do not touch the original collection. Otherwise, you could also work with single value configuration, e.g. a comma separated string or something, if you want full control.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.