dotnet/runtime
View on GitHubConfigurationManager.AppSettings getter is not thread safe and multiple instances are created
Open
#56,075 opened on Jul 21, 2021
area-System.Configurationhelp wanted
Repository metrics
- Stars
- (17,886 stars)
- PR merge metrics
- (Avg merge 12d 11h) (661 merged PRs in 30d)
Description
Description
ConfigurationManager.AppSettings getter should return a single, cached instance.
The official documentation:
The ConfigurationManager class includes members that enable you to perform the following tasks:
- Read a section from a configuration file. To access configuration information, call the GetSection method. For some sections such as appSettings and connectionStrings, use the AppSettings and ConnectionStrings classes. These members perform read-only operations, use a single cached instance of the configuration, and are multithread aware. The actual behavior is different. If the
AppSettingscached instance is not yet initialized and property is accessed concurrently, it can return multiple different instances.
Code to reproduce the issue:
var tasks = Enumerable.Range(1, 100)
.Select(_ => Task.Run(() => ConfigurationManager.AppSettings))
.ToList();
var settings = await Task.WhenAll(tasks);
var instances = settings.Distinct().ToList();
Console.WriteLine($"{instances.Count} AppSettings were created!");
if (instances.Count > 1)
{
instances[0]["key"] = "value";
if (instances.Any(appSettings => appSettings["key"] != "value"))
{
Console.WriteLine("A key set on one instance doesn't affect other created instances");
}
}
Output on my workstation with 4 core CPU:
4 AppSettings were created!
Key set on one instance doesn't affect other created instances
Configuration
- runtime: 5.0.302
- nuget:
System.Configuration.ConfigurationManager 5.0.0 - OS: Windows / Linux
- arch: x64
Regression?
No - the same issue can be reproduced on .NET 4.8 referencing the System.Configuration assembly
Other information
The code in the ConfigurationManager class is probably correct. I suspect the ClientConfigurationSystem class or some internals deeper.