2012-07-30 64 views
5

有沒有什麼方法可以在運行時從默認App.config文件以外的其他文件加載設置?我想在加載默認配置文件後執行此操作。加載屬性。在運行時從另一個文件中設置

我在Visual Studio中使用Settings.Settings GUI來爲我創建我的App.config文件。該配置文件最終看起來像這樣:

<?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> 

在代碼中,我能夠獲得這樣的設置:

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

的想法是,在應用程序運行的時候,我應該是能夠在運行時指定配置文件,並讓應用程序將配置文件加載到Properties.Settings.Default對象中,而不是使用默認的app.config文件。配置文件的格式將是相同的,但設置的值將會不同。

我知道用ConfigurationManager.OpenExeConfiguration(configFile);這樣做的方法。但是,在我運行的測試中,它不會更新Properties.Settings.Default對象以反映配置文件中的新值。


考慮了這一點後,我已經能夠想出一個我喜歡更好一點的解決方案。我相信它有一些陷阱,但我認爲它會爲我需要它做的工作。

本質上,Properties.Settings類是由Visual Studio自動生成的;它爲你生成類的代碼。我能夠找到代碼的生成位置,並添加一些函數調用來自行加載配置文件。這裏是我的加法:

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

我添加的代碼暴露了Properties.Settings.Load(string filename)函數。該函數接受一個配置文件名作爲參數。它將解析該文件並加載它在配置文件中遇到的任何設置。要恢復到原始配置,只需致電Properties.Settings.Reload()即可。

希望這可以幫助別人!

+0

這似乎真的很有希望,但我們如何使用類型 – tofutim 2015-09-21 22:57:07

回答

0

看看使用ExeConfigurationFileMap和ConfigurationManager.OpenMappedExeConfiguration。

Cracking the Mysteries of .Net 2.0 Configuration

的ExeConfigurationFileMap可以專門配置 確切路徑名機,EXE,漫遊和本地配置文件 ,都在一起,或零碎,要求 OpenMappedExeConfiguration時()。您不需要指定所有 文件,但是在創建 配置對象時將識別併合並所有文件。在使用 OpenMappedExeConfiguration時,重要的是要了解所有 級別的配置級別通過您請求的級別總是將 合併。如果您指定了一個自定義exe文件和本地配置文件 ,但未指定機器和漫遊文件,則會找到默認機器和 漫遊文件,並與指定的exe和用戶 文件合併。如果指定的文件 未被正確保持與默認文件同步,這可能會產生意想不到的後果。

1

這取決於應用程序的類型:

  1. Web應用程序& Windows應用程序 - 使用configSource XML屬性,如果你願意在同一個文件夾中的配置文件(或子文件夾)存儲爲應用程序
  2. 創建settings provider並執行IApplicationSettingsProvider。樣品herehere。您可能還需要使用IConfigurationManagerInternal接口來替換默認的.NET配置管理器。在實現提供商時,不要忘記在用戶設置和應用程序設置以及漫遊配置文件之間做出區別。

如果你想快速上手只是反編譯LocalFileSettingsProvider類(默認設置提供)並將其更改爲您的需要(您可能會發現一些useles代碼,並可能需要複製所有它所依賴的類)。

祝你好運

0

你可以包含這些類型,所以你不需要每次都手動更新源代碼。

`private void LoadSetting(System.Xml.Linq.XElement setting) { 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

是否可以處理這種任意類型 – tofutim 2015-09-21 22:57:51

相關問題