Указывает ли ConfigurationManager.AppSettings [Key] каждый раз из файла web.config?

Мне просто интересно, как работает ConfigurationManager.AppSettings [Key]?

Он читает из физического файла каждый раз, когда мне нужен ключ?

Если да, должен ли я читать все настройки приложения моего web.config в кеше, а затем читать с него?

Или ASP.NET или IIS загружает файл web.config в application_startup и только один раз.

Как проверить, доступен ли физический файл для каждого чтения?

Если я изменяю файл web.config, IIS перезапускает мое приложение, поэтому не могу проверить его таким образом.

Спасибо,

Ответ 1

Он кэшируется при первом доступе к свойству, поэтому он не считывает из физического файла каждый раз, когда вы запрашиваете значение. Вот почему необходимо перезапустить приложение Windows (или Refresh config), чтобы получить последнее значение и почему ASP. Сетевое приложение автоматически перезапускается при редактировании web.config. Почему ASP.Net жестко подключен к перезагрузке, обсуждается в ссылках в ответе Как предотвратить перезапуск приложения ASP.NET при изменении файла web.config.

Мы можем проверить это с помощью ILSpy и посмотреть на внутренности 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;
    }
}

Сначала это действительно выглядит так, что он будет получать раздел каждый раз. Глядя на GetSection:

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

Критическая линия здесь - это метод PrepareConfigSystem(); это инициализирует экземпляр поля IInternalConfigSystem, хранящегося в ConfigurationManager - конкретный тип ClientConfigurationSystem

В качестве части этой нагрузки создается экземпляр класса Configuration. Этот класс является фактически объектным представлением конфигурационного файла и, по-видимому, удерживается свойством ClientConfigurationSystem ClientConfigurationHost в статическом поле - следовательно, он кэшируется.

Вы можете проверить это эмпирически, выполнив следующее (в приложении Windows Form или WPF):

  • Запуск приложения
  • Доступ к значению в app.config
  • Внесите изменения в app.config
  • Проверить, присутствует ли новое значение
  • Вызов ConfigurationManager.RefreshSection("appSettings")
  • Проверьте, присутствует ли новое значение.

Фактически, я мог бы сэкономить некоторое время, если бы просто прочитал комментарий к RefreshSection method:-)

/// <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>

Ответ 2

Простой ответ - нет, он не всегда читает его из файла. Как некоторые предложили, если файл был изменен, IIS выполняет перезапуск, но не всегда! Если вы хотите гарантировать, что вы читаете самое последнее значение из файла, а не кеш, вам нужно вызвать что-то вроде этого:

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

И пример, который я использую в своем коде:

/// ======================================================================================
/// <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;
}

Это позволяет вам очень легко выбирать (и при чтении кода), получают ли вы последнее значение каждый раз или если вы не ожидаете, что значение изменится с момента запуска приложения.

Ответ 3

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;

Все показывают тот же LastAccessTime, который означает, что он кэшируется при запуске.

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

        DateTime fourth = file.LastAccessTime;