76

仕組みが気になりConfigurationManager.AppSettings[Key]ます。

キーが必要になるたびに物理ファイルから読み取られますか? もしそうなら、キャッシュ内の web.config のすべてのアプリ設定を読み取ってから読み取る必要がありますか?

それとも、ASP.NET または IIS は web.config ファイルをアプリケーションの起動時に 1 回だけロードしますか?

読み取りごとに物理ファイルがアクセスされるかどうかを確認するにはどうすればよいですか? web.config を変更すると、IIS によってアプリケーションが再起動されるため、その方法で検証することはできません。

4

3 に答える 3

94

プロパティへの最初のアクセス時にキャッシュされるため、値を要求するたびに物理ファイルから読み取ることはありません。これが、最新の値を取得するために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()メソッドです。これにより、ConfigurationManagerが保持するフィールドのインスタンスが初期化されますIInternalConfigSystem。具体的なタイプは次のとおりです。ClientConfigurationSystem

このロードの一部として、Configurationクラスのインスタンスがインスタンス化されます。このクラスは、事実上、構成ファイルのオブジェクト表現であり、静的フィールドのClientConfigurationSystemのClientConfigurationHostプロパティによって保持されているように見えます。したがって、キャッシュされます。

次の手順を実行することで、これを経験的にテストできます(Windowsフォームまたは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>
于 2012-11-13T09:13:46.717 に答える
8

簡単な答えはノーです。常にファイルから読み取るとは限りません。一部の人が示唆しているように、ファイルが変更された場合、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;
}

これにより、毎回最新の値を取得するか、アプリケーションの起動時から値が変更されることを期待しないかを非常に簡単に選択できます (コードを読むときに確認できます)。

于 2012-11-13T09:21:55.950 に答える
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;
于 2012-11-13T09:17:49.937 に答える