我想知道它是如何ConfigurationManager.AppSettings[Key]
工作的。
每次我需要密钥时它都会从物理文件中读取吗?如果是这样,我是否应该在缓存中读取我的 web.config 的所有应用程序设置,然后从中读取?
还是 ASP.NET 或 IIS 在应用程序启动时只加载一次 web.config 文件?
如何验证每次读取是否访问了物理文件?如果我更改 web.config,IIS 会重新启动我的应用程序,因此我无法以这种方式对其进行验证。
我想知道它是如何ConfigurationManager.AppSettings[Key]
工作的。
每次我需要密钥时它都会从物理文件中读取吗?如果是这样,我是否应该在缓存中读取我的 web.config 的所有应用程序设置,然后从中读取?
还是 ASP.NET 或 IIS 在应用程序启动时只加载一次 web.config 文件?
如何验证每次读取是否访问了物理文件?如果我更改 web.config,IIS 会重新启动我的应用程序,因此我无法以这种方式对其进行验证。
它在第一次访问属性时被缓存,因此每次请求值时它都不会从物理文件中读取。这就是为什么必须重新启动 Windows 应用程序(或刷新配置)以获取最新值的原因,以及为什么 ASP.Net 应用程序会在您编辑 web.config 时自动重新启动。答案中的参考资料讨论了为什么 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()
方法;这将初始化IInternalConfigSystem
ConfigurationManager 持有的字段的实例 - 具体类型是ClientConfigurationSystem
作为此负载的一部分,Configuration类的一个实例被实例化。此类实际上是配置文件的对象表示,并且似乎由静态字段中的 ClientConfigurationSystem 的 ClientConfigurationHost 属性持有 - 因此它被缓存。
您可以通过执行以下操作(在 Windows 窗体或 WPF 应用程序中)凭经验对此进行测试:
ConfigurationManager.RefreshSection("appSettings")
事实上,如果我只是阅读有关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>
简单的答案是否定的,它并不总是从文件中读取它。正如一些人所建议的那样,如果文件被更改,那么 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;
}
这使您可以非常轻松地选择(并在阅读代码时查看)是否每次都获取最新值,或者您是否不希望从应用程序启动时更改该值。
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;