web-dev-qa-db-fra.com

ConfigurationManager.AppSettings [Key] lit-il à chaque fois dans le fichier web.config?

Je me demande simplement comment fonctionne ConfigurationManager.AppSettings [Key]?

Est-il lu à partir du fichier physique chaque fois que j'ai besoin d'une clé?

Dans l'affirmative, dois-je lire tous les paramètres d'application de mon web.config dans un cache, puis les lire?

Ou ASP.NET ou IIS charge le fichier web.config à application_startup et une seule fois.

Comment vérifier si le fichier physique est accessible à chaque lecture?

Si je change le web.config, IIS redémarre mon application donc je ne peux pas le vérifier de cette façon.

Merci,

67
The Light

Il est mis en cache, lors du premier accès à une propriété, il ne lit donc pas le fichier physique à chaque fois que vous demandez une valeur. C'est pourquoi il est nécessaire de redémarrer une application Windows (ou Actualiser la configuration) pour obtenir la dernière valeur, et pourquoi une application ASP.Net redémarre automatiquement lorsque vous modifiez web.config. Pourquoi ASP.Net est câblé pour redémarrer est expliqué dans les références dans la réponse Comment empêcher une application ASP.NET de redémarrer lorsque le web.config est modifié .

Nous pouvons le vérifier en utilisant ILSpy et en regardant les internes de System.Configuration:

public static NameValueCollection AppSettings
{
    get
    {
        object section = ConfigurationManager.GetSection("appSettings");
        if (section == null || !(section is NameValueCollection))
        {
            throw new ConfigurationErrorsException(SR.GetString("Config_appsettings_declaration_invalid"));
        }
        return (NameValueCollection)section;
    }
}

Au début, il semble en effet qu'il obtiendra la section à chaque fois. En regardant GetSection:

public static object GetSection(string sectionName)
{
    if (string.IsNullOrEmpty(sectionName))
    {
        return null;
    }
    ConfigurationManager.PrepareConfigSystem();
    return ConfigurationManager.s_configSystem.GetSection(sectionName);
}

La ligne critique ici est la méthode PrepareConfigSystem(); ceci initialise une instance du champ IInternalConfigSystem détenu par ConfigurationManager - le type concret est ClientConfigurationSystem

Dans le cadre de cette charge, une instance de la classe Configuration est instanciée. Cette classe est en fait une représentation d'objet du fichier de configuration et semble être détenue par la propriété ClientConfigurationHost de ClientConfigurationSystem dans un champ statique - elle est donc mise en cache.

Vous pouvez tester cela empiriquement en procédant comme suit (dans une application Windows Form ou WPF):

  1. Démarrage de votre application
  2. Accéder à une valeur dans app.config
  3. Apportez une modification à app.config
  4. Vérifiez si la nouvelle valeur est présente
  5. Appeler ConfigurationManager.RefreshSection("appSettings")
  6. Vérifiez si la nouvelle valeur est présente.

En fait, j'aurais pu gagner du temps si j'avais lu le commentaire sur la méthode RefreshSection :-)

/// <summary>Refreshes the named section so the next time that it is retrieved it will be re-read from disk.</summary>
/// <param name="sectionName">The configuration section name or the configuration path and section name of the section to refresh.</param>
83
dash

La réponse simple est non, il ne le lit pas toujours depuis le fichier. Comme certains l'ont suggéré si le fichier est modifié, alors IIS effectue un redémarrage mais pas toujours! Si vous voulez garantir que vous lisez la dernière valeur du fichier et non le cache dont vous avez besoin appeler quelque chose comme ça:

ConfigurationManager.RefreshSection("appSettings");
string fromFile = ConfigurationManager.AppSettings.Get(key) ?? string.Empty;

Et un exemple que j'utilise dans mon code:

/// ======================================================================================
/// <summary>
/// Refreshes the settings from disk and returns the specific setting so guarantees the
/// value is up to date at the expense of disk I/O.
/// </summary>
/// <param name="key">The setting key to return.</param>
/// <remarks>This method does involve disk I/O so should not be used in loops etc.</remarks>
/// <returns>The setting value or an empty string if not found.</returns>
/// ======================================================================================
private string RefreshFromDiskAndGetSetting(string key)
{
    // Always read from the disk to get the latest setting, this will add some overhead but
    // because this is done so infrequently it shouldn't cause any real performance issues
    ConfigurationManager.RefreshSection("appSettings");
    return GetCachedSetting(key);
}

/// ======================================================================================
/// <summary>
/// Retrieves the setting from cache so CANNOT guarantees the value is up to date but
/// does not involve disk I/O so can be called frequently.
/// </summary>
/// <param name="key">The setting key to return.</param>
/// <remarks>This method cannot guarantee the setting is up to date.</remarks>
/// <returns>The setting value or an empty string if not found.</returns>
/// ======================================================================================
private string GetCachedSetting(string key)
{
    return ConfigurationManager.AppSettings.Get(key) ?? string.Empty;
}

Cela vous permet de choisir très facilement (et lors de la lecture du code voir) si vous obtenez la dernière valeur à chaque fois ou si vous ne vous attendez pas à ce que la valeur change depuis le démarrage de l'application.

7
Belogix
var file =
            new FileInfo(@"\\MyConfigFilePath\Web.config");

        DateTime first  = file.LastAccessTime;

        string fn = ConfigurationManager.AppSettings["FirstName"];
        Thread.Sleep(2000);

        DateTime second = file.LastAccessTime;

        string sn = ConfigurationManager.AppSettings["Surname"];
        Thread.Sleep(2000);

        DateTime third = file.LastAccessTime;

Tous affichent le même LastAccessTime, ce qui signifie qu'il est mis en cache au démarrage.

        string fn1 = ConfigurationManager.AppSettings["FirstName"];
        Thread.Sleep(2000);

        DateTime fourth = file.LastAccessTime;
1
The Light