是否每次都从web.config文件读取ConfigurationManager.AppSettings [Key]?


74

我想知道如何ConfigurationManager.AppSettings[Key]运作。

每当我需要密钥时,它是否从物理文件中读取?如果是这样,我是否应该在缓存中读取web.config的所有应用程序设置,然后从中读取?

还是ASP.NET或IIS在应用程序启动时仅加载一次web.config文件?

如何验证每次读取是否访问物理文件?如果更改了web.config,IIS将重新启动应用程序,因此无法以这种方式进行验证。

Answers:


93

它是在第一次访问属性时被缓存的,因此在您每次请求值时都不会从物理文件中读取它。这就是为什么必须重新启动Windows应用程序(或刷新配置)以获取最新值的原因,以及为什么在编辑web.config时ASP.Net应用程序会自动重新启动的原因。答案中的参考中讨论了为什么ASP.Net很难重新启动。在修改web.config时如何防止ASP.NET应用程序重新启动

我们可以使用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()方法。这将初始化IInternalConfigSystemConfigurationManager保留的字段的实例-具体类型为ClientConfigurationSystem

作为此负载的一部分,将实例化Configuration类的实例。此类实际上是配置文件的对象表示,并且似乎由ClientConfigurationSystem的ClientConfigurationHost属性保留在静态字段中-因此将对其进行缓存。

您可以通过以下操作(在Windows Form或WPF应用程序中)进行经验测试:

  1. 启动您的应用
  2. 访问app.config中的值
  3. 更改app.config
  4. 检查是否存在新值
  5. 呼叫 ConfigurationManager.RefreshSection("appSettings")
  6. 检查是否存在新值。

实际上,如果我只阅读有关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>

7

简单的答案是“否”,它并不总是从文件中读取它。正如某些人建议的那样,如果文件被更改,则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;
}

这使您可以非常容易地选择(并且在阅读代码时)是每次获取最新值还是不希望从应用程序启动时开始更改该值。


1
“不总是”是什么意思!这是设计使然,我已经了解到IIS会重新启动应用程序并重新加载配置。
The Light

1
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;
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.