dotnet/runtime

ConfigurationManager.AppSettings getter is not thread safe and multiple instances are created

Open

#56.075 aberto em 21 de jul. de 2021

Ver no GitHub
 (3 comments) (3 reactions) (0 assignees)C# (5.445 forks)batch import
area-System.Configurationhelp wanted

Métricas do repositório

Stars
 (17.886 stars)
Métricas de merge de PR
 (Mesclagem média 12d 11h) (661 fundiu PRs em 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 AppSettings cached 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.

Guia do colaborador