2012-07-30 7 views
5

Esiste un modo per caricare le impostazioni da un file diverso dal file App.config predefinito in fase di runtime? Mi piacerebbe farlo dopo che è stato caricato il file di configurazione di default.Caricamento proprietà. Impostazioni da un file diverso in fase di esecuzione

Io uso la GUI Settings.Settings in Visual Studio per creare il mio file App.config per me. Il file di configurazione finisce per assomigliare a questo:

<?xml version="1.0" encoding="utf-8" ?> 
    <configuration> 
     <configSections> 
      <sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" > 
     <section name="SnipetTester.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" /> 
    </sectionGroup> 
    </configSections> 
     <applicationSettings> 
     <SnipetTester.Properties.Settings> 
      <setting name="SettingSomething" serializeAs="String"> 
      <value>1234</value> 
      </setting> 
     </SnipetTester.Properties.Settings> 
     </applicationSettings> 
    </configuration> 

In codice, sono in grado di accedere alle impostazioni in questo modo:

Console.WriteLine("Default setting value: " + Properties.Settings.Default.SettingSomething); 

L'idea è che quando si esegue l'applicazione, dovrei essere in grado di specificare un file di configurazione in fase di esecuzione e di caricare l'applicazione nel file di configurazione nell'oggetto Properties.Settings.Default invece di utilizzare il file predefinito app.config. I formati dei file di configurazione sarebbero gli stessi, ma i valori delle impostazioni sarebbero diversi.

Conosco un modo per farlo con ConfigurationManager.OpenExeConfiguration(configFile);. Tuttavia, nei test che ho eseguito, non aggiorna l'oggetto Properties.Settings.Default per riflettere i nuovi valori dal file di configurazione.


Dopo pensando a questo un po 'più a lungo, sono stato in grado di trovare una soluzione che mi piace un po' meglio. Sono sicuro che ha alcune insidie, ma penso che funzionerà per quello che ho bisogno di fare.

In sostanza, la classe Properties.Settings viene generata automaticamente da Visual Studio; genera il codice per la classe per te. Sono stato in grado di trovare dove è stato generato il codice e aggiungere alcune chiamate di funzione per caricare un file di configurazione da solo. Ecco la mia aggiunta:

internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase 
{ 
    //Parses a config file and loads its settings 
    public void Load(string filename) 
    { 
     System.Xml.Linq.XElement xml = null; 
     try 
     { 
      string text = System.IO.File.ReadAllText(filename); 
      xml = System.Xml.Linq.XElement.Parse(text); 
     } 
     catch 
     { 
      //Pokemon catch statement (gotta catch 'em all) 

      //If some exception occurs while loading the file, 
      //assume either the file was unable to be read or 
      //the config file is not in the right format. 
      //The xml variable will be null and none of the 
      //settings will be loaded. 
     } 

     if(xml != null) 
     { 
      foreach(System.Xml.Linq.XElement currentElement in xml.Elements()) 
      { 
       switch (currentElement.Name.LocalName) 
       { 
        case "userSettings": 
        case "applicationSettings": 
         foreach (System.Xml.Linq.XElement settingNamespace in currentElement.Elements()) 
         { 
          if (settingNamespace.Name.LocalName == "SnipetTester.Properties.Settings") 
          { 
           foreach (System.Xml.Linq.XElement setting in settingNamespace.Elements()) 
           { 
            LoadSetting(setting); 
           } 
          } 
         } 
         break; 
        default: 
         break; 
       } 
      } 
     } 
    } 

    //Loads a setting based on it's xml representation in the config file 
    private void LoadSetting(System.Xml.Linq.XElement setting) 
    { 
     string name = null, type = null, value = null; 

     if (setting.Name.LocalName == "setting") 
     { 
      System.Xml.Linq.XAttribute xName = setting.Attribute("name"); 
      if (xName != null) 
      { 
       name = xName.Value; 
      } 

      System.Xml.Linq.XAttribute xSerialize = setting.Attribute("serializeAs"); 
      if (xSerialize != null) 
      { 
       type = xSerialize.Value; 
      } 

      System.Xml.Linq.XElement xValue = setting.Element("value"); 
      if (xValue != null) 
      { 
       value = xValue.Value; 
      } 
     } 


     if (string.IsNullOrEmpty(name) == false && 
      string.IsNullOrEmpty(type) == false && 
      string.IsNullOrEmpty(value) == false) 
     { 
      switch (name) 
      { 
       //One of the pitfalls is that everytime you add a new 
       //setting to the config file, you will need to add another 
       //case to the switch statement. 
       case "SettingSomething": 
        this[name] = value; 
        break; 
       default: 
        break; 
      } 
     } 
    } 
} 

Il codice ho aggiunto espone una funzione Properties.Settings.Load(string filename). La funzione accetta un nome file di configurazione come parametro. Analizzerà il file e caricherà tutte le impostazioni che incontra nel file di configurazione. Per ripristinare la configurazione originale, è sufficiente chiamare Properties.Settings.Reload().

Spero che questo possa aiutare qualcun altro!

+0

questo sembra davvero promettente, ma come possiamo usare i tipi – tofutim

risposta

0

Guardare utilizzando ExeConfigurationFileMap e ConfigurationManager.OpenMappedExeConfiguration.

Vedi Cracking the Mysteries of .Net 2.0 Configuration

L'ExeConfigurationFileMap consente di configurare specificamente le percorsi esatti da lavorare, exe, roaming e file di configurazione locali, tutti insieme, o frammentario, quando si chiama OpenMappedExeConfiguration(). Non è necessario specificare tutti i file , ma tutti i file verranno identificati e uniti quando viene creato l'oggetto di configurazione . Quando si utilizza OpenMappedExeConfiguration, è importante comprendere che tutti i livelli di configurazione di fino al livello richiesto saranno sempre uniti. Se si specifica un exe personalizzato e un file di configurazione locale, ma non si specifica un file di macchina e di roaming, i file di roaming e di macchina standard verranno trovati e uniti con i file exe e utente specificati. Ciò può avere conseguenze impreviste se i file specificati non sono stati mantenuti correttamente sincronizzati con i file predefiniti.

1

Dipende dal tipo di applicazione:

  1. Web Application & Applicazione Windows - utilizzare l'attributo configSource XML se si è disposti a memorizzare i file di configurazione nella stessa cartella (o sottocartelle) come l'applicazione
  2. Creare un settings provider e implementare anche IApplicationSettingsProvider. Campioni here e here. Potrebbe anche essere necessario utilizzare l'interfaccia IConfigurationManagerInternal per sostituire il gestore di configurazione .NET predefinito. Quando si implementa il provider, non dimenticare di fare la differenza tra le impostazioni utente e le impostazioni dell'applicazione e i profili di roaming.

Se si vuole iniziare rapidamente appena decompilare la classe LocalFileSettingsProvider (il fornitore di impostazioni di default) e cambiare alle proprie esigenze (si potrebbe trovare qualche codice useles e potrebbe aver bisogno di replicare tutte le classi da cui dipende).

Buona fortuna

0

È possibile includere i tipi in modo non è necessario aggiornare manualmente la fonte ogni volta.

`vuoto privato LoadSetting (impostazione System.Xml.Linq.XElement) { string name = null, type = null; string value = null;

 if (setting.Name.LocalName == "setting") 
     { 
      System.Xml.Linq.XAttribute xName = setting.Attribute("name"); 
      if (xName != null) 
      { 
       name = xName.Value; 
      } 

      System.Xml.Linq.XAttribute xSerialize = setting.Attribute("serializeAs"); 
      if (xSerialize != null) 
      { 
       type = xSerialize.Value; 
      } 

      System.Xml.Linq.XElement xValue = setting.Element("value"); 
      if (xValue != null) 
      { 
       if (this[name].GetType() == typeof(System.Collections.Specialized.StringCollection)) 
       { 
        foreach (string s in xValue.Element("ArrayOfString").Elements()) 
        { 
         if (!((System.Collections.Specialized.StringCollection)this[name]).Contains(s)) 
          ((System.Collections.Specialized.StringCollection)this[name]).Add(s); 
        } 
       } 
       else 
       { 
        value = xValue.Value; 
       } 

       if (this[name].GetType() == typeof(int)) 
       { 
        this[name] = int.Parse(value); 
       } 
       else if (this[name].GetType() == typeof(bool)) 
       { 
        this[name] = bool.Parse(value); 
       } 
       else 
       { 
        this[name] = value; 
       } 

      } 
     }` 
+0

è possibile gestirlo per tipo arbitrario – tofutim

Problemi correlati