-
Notifications
You must be signed in to change notification settings - Fork 201
Support arrays as values in JSON configuration source #115
Comments
Any update on this? It seems like a minimum requirement for all but the very simplest configuration. I'd like to know if I can count on it being in the release or if I'm going to have to roll my own config system. |
For now config values are stored in |
@victorhurdugaci Assigning this to you so that getting a design together for it doesn't fall through the cracks. |
Hi folks! Any progress on this? :) |
Can you guys drop me some examples of what you want to write in the config files to help drive this? Examples of the types of configuration, simple and complex ideally. |
My primary use case right now is Autofac configuration. In that, you can configure different components and modules to be registered with Autofac. For example, I might imagine something like this: {
"components": [
{
"type": "Some.ConcreteType",
"services": [
"First.Exposed.IInterface",
"Second.Exposed.IInterface"
],
"parameters": {
"simpleParam": "SimpleValue",
"listParam": [1, 2, 3],
"dictParam": {
"name": "value"
}
}
},
{
"type": "Some.ConcreteType",
"services": ["Different.IInterface"]
}
],
"modules": [
"First.ModuleType",
"Second.ModuleType",
"Third.ModuleType"
]
} The interesting bits in that example from an ordinal list perspective:
|
I've just ran into this problem myself, I'd like to use this config but I can't. I think I'd be happy with at least basic types support for arrays initially (as in strings, numbers) {
"Cameras": {
"Addresses": [ "192.168.0.12", "192.168.0.24" ]
}
} |
For us in R4MVC it is just arrays of basic types too - strings in particular: {
"staticFilesFolders": [ "Scripts", "Content" ]
} |
👍 Looking forward to seeing this get implemented. I have a lot of need for this functionality |
@davidfowl @lodejard @glennc let's discuss this today in the design meeting and close on the spec. We still need to figure out what to do with the configurations that don't support arrays by default (e.g env variables) |
What if this: "modules": [
"First.ModuleType",
"Second.ModuleType",
"Third.ModuleType"
] is just syntax sugar for this: "modules": {
"0":"First.ModuleType",
"1":"Second.ModuleType",
"2":"Third.ModuleType"
} You iterate over the values of the collection by using Should also note that the following is consumable with the same code as the one above, assuming we support this syntax as the way to go: "modules": {
"Label for first module type":"First.ModuleType",
"Label for second module type":"Second.ModuleType",
"Label for third module type":"Third.ModuleType"
} |
I don't feel strongly about whether it's just a syntactic sugar for auto-generated numeric "keys." That should work. As long as there is no unique constraint enforced on the values it should be just fine.
|
GetSubKeys returns an IEnumerable of KeyValue pairs, which you can count. You might need to know what keys could contain collections, but you would need to know that anyway right? or am I missing something? Set is interesting, it doesn't actually make any changes to the configuration source. There is no way to commit config changes back to the source. All you are doing is updating the configuration object you call it on. Having Set support a collection though is probably fine. |
I could be missing something with
But there is no
I'm not sure if I'm even close, there. I figure you've got something in mind for that "iterate over the list" thing so maybe if you could post it just for clarification, it'd help solidify things. |
I've recently written a small POC with 'module' discovery that utilised the following pattern: Config{
"Installers": {
"Include": {
"Module1": "My.Custom.Installer.Module1",
"Module2": "My.Custom.Installer.Module2",
"Module3": "My.Custom.Installer.Module3"
}
}
} Codevar configRoot = "Installers:Include";
var includes = configuration.GetSubKeys(configRoot)
.Select(kvp => kvp.Key)
.Select(k => configuration.Get($"{configRoot}:{k}"));
ConcernsThere's a few things I don't like about this pattern.
@glennc I just re-read your comment. Ultimately if the following "modules": [
"First.ModuleType",
"Second.ModuleType",
"Third.ModuleType"
] could be accessed as config.Get("modules:0"); //=> "First.ModuleType"
config.Get<IEnumerable<string>>("modules"); //=> "First.ModuleType", "Second.ModuleType", "Third.ModuleType" That would be awesome! |
@Kieranties mentioned something I didn't consider - overrides. If you merge two ordinal collections together... do you get a union of all the elements or do you get just the last collection to get merged in? |
Below is a summary of the discussion and the spec. TL;DR;
How it looks likeAll the configurations below are equivalent: json
which is actually syntactic sugar for
For json arrays, the indices are implied to be 0, 1, 2, ... environment variables
xml
ini
command line arguments
Usage
Overwrite and concat rulesOverwrite The last one wins at index level If this comes first
and this second
the result is:
Because "3.4.5.6" gets index "1" and gets overwritten by the value from xml (which has name = "1") Concat/append If you want to append, use named indices to avoid conflicts If this comes first
and this second
the result is
Sorting
Caveats
and
are perfectly valid and the config system will read them differently. The second "ip" is not an array of one element. OptionsOptions will support model binding to arrays. Will be part of the same change and that's where we encourage everyone to consider arrays. Config will not have arrays as first class citizens. |
The ini example would be: [ip] Because in the other examples "addresses:" isn't part of the key Sent from mobile device From: Victor Hurdugacimailto:[email protected] Below is a summary of the discussion and the spec. TL;DR;
How it looks like All the configurations below are equivalent: json "ip": [ which is actually syntactic sugar for "ip": { For json arrays, the indices are implied to be 0, 1, 2, ... environment variables SET ip:0 = 1.2.3.4 xml 1.2.3.4 ini [addresses] command line arguments --ip:0 = 1.2.3.4 --ip:1 = 3.4.5.6 --ip:2 = 2.5.43.4 Usage Configuration config = new Configuration(); var subkeys = config.GetSubKeys("ip"); foreach(var ip in subkeys) Overwrite and concat rules Overwrite The last one wins at index level If this comes first "ip": [ and this second 0.0.0.0 the result is: 1.2.3.4 Because "3.4.5.6" gets index "1" and gets overwritten by the value from xml (which has name = "1") Concat/append If you want to append, use named indices to avoid conflicts If this comes first "ip": [ and this second 0.0.0.0 the result is 1.2.3.4 Sorting
Caveats "ip": [ and "ip": "0.0.0.0" are perfectly valid and the config system will read them differently. The second "ip" is not an array of one element. Options Options will support model binding to arrays. Will be part of the same change and that's where we encourage everyone to consider arrays. Config will not have arrays as first class citizens. — |
In Asp.net Core 1.1 the syntax to get the Configuration.GetSection("Key").GetChildren() I use this to store allowed origins for CORS requests: services.AddCors(options =>
{
options.AddPolicy("AllowSpecificOrigins", builder =>
{
builder.WithOrigins(Configuration.GetSection("Auth:Origins").GetChildren().Select(c => c.Value).ToArray())
.AllowAnyHeader()
.AllowAnyMethod();
});
}); Would be nice if this were in the documentation. |
@pholly Another approach is to use the Bind method as follows: var origins = new List<string>();
Configuration.GetSection("Auth:Origins").Bind(origins); |
Need to figure out a proper representation of arrays when they used as values. Also need to figure out the corresponding things in xml and ini files.
The text was updated successfully, but these errors were encountered: