2009-12-08 11 views
6

Chociaż istnieje wiele postów dotyczących plików konfiguracyjnych .net, uważam, że moje wymagania nie pozwalają na żadne z proponowanych rozwiązań (lub nie rozumiem wystarczająco dużo procesu, aby to działało dla mnie).Jak używać plików konfiguracyjnych .NET (app.config, settings.settings) do zapisywania i przywracania wszystkich danych aplikacji?

Sytuacja jest taka, że ​​mam aplikację Windows Forms (równie dobrze mogłaby to być inna aplikacja), która wiąże określone pola wprowadzania użytkowników (np. Adres IP), a także właściwości formularza (rozmiar okna, itp.) Z ustawieniami aplikacji (w obszarze Właściwości-> Ustawienia). Z tego co rozumiem, te ustawienia są takie same jak te przedstawione w pliku app.config mojego projektu, więc powinienem móc używać klasy System.Configuration.ConfigurationManager do manipulowania tymi ustawieniami.

Co chcę zrobić, to pozwolić użytkownikowi na eksport i import wszystkich zapisanych ustawień. Zamiast robienia serializacji jakiegoś niestandardowego obiektu lub pracy z plikami INI, pomyślałem, że łatwiej będzie po prostu zapisać i zastąpić plik konfiguracyjny, z którego korzysta aplikacja.

Jest to stosunkowo łatwe, można zapisać bieżące ustawienia w określonym pliku:

internal static void Export(string settingsFilePath) 
{ 
    var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal); 
    config.SaveAs(settingsFilePath); 
} 

Jednak przywrócenie plik konfiguracyjny, aby zastąpić bieżące ustawienia okazuje się trudne. Wydaje się, że mogę otworzyć plik konfiguracyjny Podobnie jak

var newConfig = ConfigurationManager.OpenExeConfiguration(settingsFilePath) 

ale nie widzę sposobu, aby całkowicie zastąpić wszystkie ustawienia w bieżącej konfiguracji z tych z importowanego pliku. [Edytuj: To przeciążenie ma otrzymać ścieżkę pliku .exe, a nie pliku .config. Otwarcie pliku exe w ten sposób spowoduje prawdopodobnie wyjątek ConfigurationErrorsException, jeśli kod wywołujący nie odwołuje się do tych samych zestawów w pliku konfiguracyjnym.]

Być może muszę użyć tylko metod opisanych w other posts, aby zastąpić tylko część konfiguracja, a nie całość, ale nie widzę, jak to by działało w tym momencie.

Wszelkie pomysły? Czy podążam właściwą ścieżką, czy powinienem po prostu użyć plików INI (lub czegoś innego)?

Odpowiedz

1

Nie sądzę, aby przesłonięcie całego pliku konfiguracyjnego było dobrym pomysłem. Niektóre ustawienia w tym pliku mogą zawierać ustawienia, które będą przetwarzane bardzo wcześnie, zanim któryś z twoich kodów miał szansę zrobić cokolwiek, tj. Te związane z uruchomieniem .NET CLR.

+0

Wydaje się, że masz rację o nie manipulowanie cały plik. W pamięci, co najmniej, istnieje wiele więcej sekcji niż tylko jednym „appSettings”, który myślę, że jestem zainteresowany Aby zobaczyć, co mam na myśli, spróbuj var currentConfig = ConfigurationManager.OpenExeConfiguration (ConfigurationUserLevel.PerUserRoamingAndLocal); currentConfig.Dump(); w LINQPad. – Pat

+0

Odkryłem, że nie jest to wartość "appSettings", którą chciałem zmienić, ale wartość "userSettings". W szczególności jest to węzeł podrzędny . – Pat

3

Ponieważ app.config plik jest prosty plik xml można załadować go do XDocument:

string path = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile; 
XDocument doc = XDocument.Load(path); 
//Do your modifications to section x 
doc.Save(path); 
ConfigurationManager.RefreshSection("x"); 

I poprawił() kod XDocument.Load według @ komentarzu Pat

+0

Dziękujemy za polecenie, ale podana ścieżka nie jest odpowiednia do zmiany ustawień użytkownika. Również w przypadku, gdy ktoś inny chce to wypróbować, Load jest statyczną metodą klasy XDocument, więc składnia to var doc = XDocument.Load (path) ;. Będę kontynuował czytanie i zastępowanie sekcji pliku XML, aby sprawdzić, czy ta metoda działa, ale bez powodzenia. – Pat

+0

Ścieżka powinna wskazywać na App.config, gdzie myślałem, że sekcja, którą chcesz manipulować, jest. – Manu

3

Najlepiej jest NIE zapisywać do pliku app.config, ale użyć pliku ustawień do zapisania zmodyfikowanych ustawień użytkownika. Pliki app.config i web.config powinny być używane tylko dla wartości tylko do odczytu.

+0

OK, ale jak to się robi? Korzystam już z pliku ustawień, aby zachować dane użytkownika między uruchomieniami aplikacji, ale jak mogę zapisać i przywrócić te informacje jako osobny plik (import/eksport)? – Pat

+0

Jako poniższy post z Manu, pomyśl o nim jako o pliku XML. – Kenoyer130

+0

Jeszcze raz, jak to się robi? Rozumiem, że ustawienia "plik" to tak naprawdę tylko app.config, ponieważ jest to miejsce, w którym przechowywane są ustawienia. Wyjaśnienia? – Pat

0

Dzięki sugestii Manu, aby po prostu odczytać plik jako XML, zhakowałem razem this solution. (Działa tylko w bieżącej formie dla właściwości zapisanych jako łańcuchy znaków, takich jak właściwość Text w TextBox. Nie zadziała, na przykład, jeśli utrzymasz właściwość Value kontrolki NumericUpDown.) To działa za pomocą Export ze ścieżką do pliku, aby zapisać, który tworzy plik jak poniżej:

<?xml version="1.0" encoding="utf-8"?> 
<configuration> 
    <userSettings> 
     <HawkConfigGUI.Properties.Settings> 
      <setting name="FpgaFilePath" serializeAs="String"> 
       <value>testfpga</value> 
      </setting> 
      <setting name="FirmwareFilePath" serializeAs="String"> 
       <value>test</value> 
      </setting> 
     </HawkConfigGUI.Properties.Settings> 
    </userSettings> 
</configuration> 

Potem zaimportować plik i wszystkie ustawienia są zmieniane w aplikacji (nie zapomnij do .Save() w pewnym momencie). Jeśli coś pójdzie nie tak, ustawienia zostaną przywrócone.

using System; 
using System.Configuration; 
using System.IO; 
using System.Linq; 
using System.Xml.Linq; 
using System.Xml.XPath; 
using AedUtils; 

namespace HawkConfigGUI 
{ 
    public static class SettingsIO 
    { 
     private static NLog.Logger _logger = NLog.LogManager.GetCurrentClassLogger(); 

     internal static void Import(string settingsFilePath) 
     { 
      if (!File.Exists(settingsFilePath)) 
      { 
       throw new FileNotFoundException(); 
      } 

      var appSettings = Properties.Settings.Default; 
      try 
      { 
       // Open settings file as XML 
       var import = XDocument.Load(settingsFilePath); 
       // Get the <setting> elements 
       var settings = import.XPathSelectElements("//setting"); 
       foreach (var setting in settings) 
       { 
        string name = setting.Attribute("name").Value; 
        string value = setting.XPathSelectElement("value").FirstNode.ToString(); 

        try 
        { 
         appSettings[name] = value; // throws SettingsPropertyNotFoundException 
        } 
        catch (SettingsPropertyNotFoundException spnfe) 
        { 
         _logger.WarnException("An imported setting ({0}) did not match an existing setting.".FormatString(name), spnfe); 
        } 
        catch (SettingsPropertyWrongTypeException typeException) 
        { 
         _logger.WarnException(string.Empty, typeException); 
        } 
       } 
      } 
      catch (Exception exc) 
      { 
       _logger.ErrorException("Could not import settings.", exc); 
       appSettings.Reload(); // from last set saved, not defaults 
      } 
     } 

     internal static void Export(string settingsFilePath) 
     { 
      var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal); 
      config.SaveAs(settingsFilePath); 
     } 
    } 
} 
+1

Chciałbym wiedzieć, dlaczego ktoś uważa to za złą odpowiedź, a także, że ktoś daje "dobrą" odpowiedź. Wszystko, co muszę powiedzieć, to to, że ten kod * działa * i nie przedstawiono żadnych innych rozwiązań roboczych. – Pat

+0

Nawiasem mówiąc, to rozwiązanie * nie * manipuluje plikiem app.config. Modyfikuje wersję pliku user.config w pamięci, która jest przenoszona do pliku przy zamknięciu aplikacji. – Pat

Powiązane problemy