Указывает ли 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;