Skip to content

ServiceCollection.Configure<ConcurrentDictionary<string, T>>(IConfigurationSection) fails in NET7 #78994

@matthewDDennis

Description

@matthewDDennis

Description

I have an ModuleCollection class which is

   /// <summary>
    /// The set of modules for backend processing.
    /// </summary>
    public class ModuleCollection : ConcurrentDictionary<string, ModuleConfig>
    {
        /// <summary>
        /// This constructor allows our modules collection to be case insensitive on the key.
        /// </summary>
        public ModuleCollection() : base(StringComparer.OrdinalIgnoreCase) { }
    }

In NET6

            services.Configure<ModuleCollection>(configuration.GetSection("Modules"));

would load the ModuleCollection with the ModuleConfigs from multiple modulesettings.json files that had been registered with the ConfigurationBuilder. TheIOption<ModuleCollection>injected would have the populated collection as its value.

In NET7 the IOption<ModuleCollection>.Value is an empty ModuleCollection

I worked around this by

            services.AddOptions<ModuleCollection>()
                    .Configure(moduleCollection =>
                    {
                        var moduleNames = configuration.GetSection("Modules").GetChildren().Select(x => x.Key).ToList();
                        foreach (var moduleName in moduleNames)
                        {
                            if (moduleName is not null)
                            {
                                ModuleConfig moduleConfig = new ModuleConfig();
                                configuration.Bind($"Modules:{moduleName}", moduleConfig);
                                moduleCollection.TryAdd(moduleName, moduleConfig);
                            }
                        }
                    });

Reproduction Steps

see above

Expected behavior

Same as NET6
IOption<ModuleCollection>.Value contains the collection of ModuleConfigs/

Actual behavior

The IOption<ModuleCollection>.Value is an empty collection.

Regression?

It worked on NET6

Known Workarounds

            ModuleCollection moduleCollection = new();
            services.AddOptions<ModuleCollection>()
                    .Configure(moduleCollection =>
                    {
                        var moduleNames = configuration.GetSection("Modules").GetChildren().Select(x => x.Key).ToList();
                        foreach (var moduleName in moduleNames)
                        {
                            if (moduleName is not null)
                            {
                                ModuleConfig moduleConfig = new ModuleConfig();
                                configuration.Bind($"Modules:{moduleName}", moduleConfig);
                                moduleCollection.TryAdd(moduleName, moduleConfig);
                            }
                        }
                    });

Configuration

NET7, VS2022 17.4.1

Other information

I can bind to a single ModuleConfig, just the binding to the dictionary is failing, so it is probably in the Dictionary Binder in NET7.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions