2012-11-13 19 views
64

Mi chiedo come funziona ConfigurationManager.AppSettings [Chiave]?ConfigurationManager.AppSettings [Chiave] legge ogni volta dal file web.config?

Legge dal file fisico ogni volta che ho bisogno di una chiave?

In tal caso, dovrei leggere tutte le impostazioni dell'app del mio web.config in una cache e leggerlo da esso?

Oppure ASP.NET o IIS carica il file web.config su application_startup e solo una volta.

Come verificare se il file fisico è accessibile da ogni lettura?

Se cambio il web.config, IIS riavvia la mia applicazione, quindi non può verificarla in questo modo.

Grazie,

risposta

78

si arriva nella cache, al primo accesso di un immobile, in modo che non lette dal file fisico ogni volta che si chiede per un valore. Questo è il motivo per cui è necessario riavviare un'app Windows (o Refresh config) per ottenere il valore più recente e perché un'app ASP.Net si riavvia automaticamente quando si modifica web.config. Perché ASP.Net è cablato per riavviare è discusso nei riferimenti nella risposta How to prevent an ASP.NET application restarting when the web.config is modified.

Possiamo verificarlo utilizzando ILSpy e guardando le internals di 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; 
    } 
} 

Dapprima questo effettivamente assomigliare otterrà sezione sempre. Guardando GetSection:

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

La linea critica qui è il metodo PrepareConfigSystem(); questo inizializza un'istanza del campo IInternalConfigSystem detenuto dal ConfigurationManager - il tipo concreto è ClientConfigurationSystem

Come parte di questo carico, viene istanziata un'istanza della classe Configuration. Questa classe è effettivamente una rappresentazione dell'oggetto del file di configurazione e sembra essere mantenuta dalla proprietà ClientConfigurationHost di ClientConfigurationSystem in un campo statico, quindi è memorizzata nella cache.

Si potrebbe verificare questa empiricamente nel modo seguente (in un'applicazione Windows Form o WPF):

  1. Avvio App fino
  2. accesso un valore in app.config
  3. Apportare una modifica al app.config
  4. controllare per vedere se il nuovo valore è presente
  5. chiamata ConfigurationManager.RefreshSection("appSettings")
  6. controllare per vedere se il nuovo valore è presente.

In realtà, avrei potuto salvare me stesso un po 'di tempo se avessi appena letto il commento sul metodo 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> 
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; 

Tutti mostrano lo stesso LastAccessTime che significa che è memorizzato nella cache all'avvio.

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

     DateTime fourth = file.LastAccessTime; 
7

La risposta semplice è no, non sempre viene letta dal file. Come alcuni hanno suggerito se il file viene modificato, IIS esegue un riavvio ma non sempre! Se si vuole garantire che si sta leggendo l'ultima valore dal file e non la cache è necessario chiamare qualcosa di simile:

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

E un esempio che uso nel mio codice:

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

Ciò consente di scegliere molto facilmente (e durante la lettura del codice vedere) se si sta ottenendo l'ultimo valore ogni volta o se non si prevede che il valore cambi da quando l'applicazione si avvia.

+1

cosa intendi con "non sempre"! questo è in base alla progettazione, ho capito che IIS riavvia l'app e ricarica la configurazione. –