PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : C# .NET - Aktuelle Methode, um Applikationssettings zu speichern/lesen?


AwesomeSauce
2011-01-15, 18:37:25
Hi zusammen

Ich sitze im Moment gerade an einer .NET Applikation und benutze dafür die Visual Studio 2010 C# IDE. Nun habe ich vor, einige Variablen im Programm zur Laufzeit in einem separaten .cfg oder .ini File zu speichern oder davon zu lesen.

Scheinbar hat aber Microsoft den Support für ini-Files schon länger eingestellt. Auch sonst bin ich auf keine befriedigende Methode gekommen, die nicht die Einbindung von Fremdcode voraussetzt (ini-Parser gibt es ja genug). Auch vor der Erstellung einer Klasse, die dann sämtliche Einstellungsparameter enthält und serialisierbar/deserialisierbar ist, schrecke ich zurück.

Deswegen frage ich mal die .NET-User unter euch. Welche Methode ist aktuell die meistgenutzte und "akzeptierteste" Methode, um Variablen in einem separaten File (.cfg, .config etc.) abzulegen und wieder einzubinden (zur Laufzeit)?

Vielen Dank für eure Hilfe!

PatkIllA
2011-01-15, 19:03:34
Du kannst in den Projekteigenschaften unter Settings Einstellungen verwalten. Kannst direkt per Designer getypte Properties anlegen. Wobei der AFAIK mit jeder Programmversion einen neuen Ordner anlegt. Das kann man aber auch umbiegen.

Da wir gelegentlich auch mal hierarchische Daten haben erzeugen wir uns selbst XML Dokumente. Das ist ja schnell gecodet.

AwesomeSauce
2011-01-15, 19:28:40
Danke erstmal. Anscheinend sind aber die Properties, die damit angelegt werden, read-only. Ich müsste aber definitiv auch Werte schreiben können. Auch sind die generierten app.config-Files nicht gerade idiotensicher zu ändern, von einem Userstandpunkt gesehen natürlich.

PatkIllA
2011-01-15, 19:35:36
Du kannst doch den Scope zwischen User und Application wechseln.
Die Applicationsweiten Werte kann man nicht ändern, da ein Programm nicht in sein Programmverzeichnis schreiben darf.

AwesomeSauce
2011-01-15, 20:08:36
Ich habe mal folgende Felder angelegt:
http://www.abload.de/img/problem1moky.png (http://www.abload.de/image.php?img=problem1moky.png)

Das Lesen funktioniert zwar:
http://www.abload.de/img/problem2cq9y.png (http://www.abload.de/image.php?img=problem2cq9y.png)

Aber wenn ich etwas schreiben möchte, wird es nicht übernommen:
http://www.abload.de/img/problem3wr89.png (http://www.abload.de/image.php?img=problem3wr89.png)

Wahrscheinlich mache ich mich gerade zum Deppen und mache etwas vollkommen verrücktes:redface:

PatkIllA
2011-01-15, 22:10:24
Ich würde es mal mit einem anschließenden Save() versuchen ;)

Sephiroth
2011-01-15, 22:17:06
hm, speichern? http://msdn.microsoft.com/en-us/library/aa730869%28VS.80%29.aspx

AwesomeSauce
2011-01-15, 22:25:50
Die Settings werden jetzt zwar gespeichert (dank an PatkIllA), aber ich sehe noch nicht, wo ich diese dann ausserhalb der Applikation verändern könnte. Denn das wäre eigentlich das Ziel, dass ich in einem externen File ganz einfach ein paar Parameter verändern kann. Die app.config behält ja die Default-Werte...

ESAD
2011-01-15, 23:41:37
du kannst nicht in den app ordner schreiben darum landet das wo anders.
-> %userprofile%\appdata\local oder %userprofile%\Local Settings\Application Data abhängig von der windowsversion für user spezifische einstellungen. Wenns nicht anwendabhängig ist dann C:\users oder C:\Documents and Settings für alle anwenderprofile (z.B. C:\users\public\appdata\local).

-tk|doc-
2011-01-17, 10:36:47
Ich stand vor kurzem vor dem gleichen Problem wie der TS. Habe es dann mit der app.config versucht, und und und. Kam aber nicht zum gewünschten Ergebnis für meine Problemstellung.

Dann habe ich die ini.Klasse entdeckt, mit der man super schreiben und lesen kann. Ich werde es aber noch später zu einer XML-Konfiguration ändern. Aber es läuft vorerst schnell als Workaround.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Text.RegularExpressions;

namespace INI-Klasse
{
/// <summary>
/// Klasse, um Dateien im Ini-Format zu verwalten.
/// </summary>
public class INIFile
{
/// <summary>
/// Inhalt der Datei
/// </summary>
private List<string> lines = new List<string>();

/// <summary>
/// Anzahl der Zeilen in der INIDatei
/// </summary>
public int LineCount
{
get { return lines.Count; }
}

/// <summary>
/// Verzeichnis der Datei
/// </summary>
/// <returns></returns>
public string FileDirectory
{
get { return Path.GetDirectoryName(FileName); }
}

/// <summary>
/// Voller Name der Datei bzw Titel der INI
/// </summary>
/// <returns></returns>
public string FileName
{
get { return FileName; }
}

/// <summary>
/// Voller Pfad und Name der Datei bzw Titel der INI
/// </summary>
private string fileName = "";

/// <summary>
/// Gibt an, welche Zeichen als Kommentarbeginn
/// gewertet werden sollen. Dabei wird das erste
/// Zeichen defaultmäßig für neue Kommentare
/// verwendet.
/// </summary>
private string CommentCharacters = ";#";

/// <summary>
/// Regulärer Ausdruck fär einen Kommentar in einer Zeile
/// </summary>
private string regCommentStr = "";

/// <summary>
/// Regulärer Ausdruck für einen Eintrag
/// </summary>
private Regex regEntry = null;

/// <summary>
/// Regulärer Ausdruck für einen Bereichskopf
/// </summary>
private Regex regCaption = null;

/// <summary>
/// Änderungen an einem Eintrag vornehmen. Achtung CaseSensitive!
/// </summary>
public string this[string Caption, string Entry]
{
get
{
return getValue(Caption, Entry, true);
}
set
{
setValue(Caption, Entry, value.ToString(), true, false);
}
}

/// <summary>
/// Leerer Standard-Konstruktor
/// </summary>
public INIFile()
{
regCommentStr = @"(\s*[" + CommentCharacters + "](?<comment>.*))?";
regEntry = new Regex(@"^[ \t]*(?<entry>([^=])+)=(?<value>([^=" + CommentCharacters + "])+)" + regCommentStr + "$");
regCaption = new Regex(@"^[ \t]*(\[(?<caption>([^\]])+)\]){1}" + regCommentStr + "$");
}

/// <summary>
/// Konstruktor, welcher sofort eine Datei einliest
/// </summary>
/// <param name="filename">Name der einzulesenden Datei</param>
public INIFile(string filename)
: this()
{
if (!File.Exists(filename))
throw new IOException("File " + filename + " not found");

Read(File.ReadAllText(filename));
}

/// <summary>
/// Methode die einen string im INI-Format einließt
/// </summary>
/// <param name="iniFile">String im INI-Format</param>
public void Read(string iniFile)
{
lines.AddRange(iniFile.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.None));
}

/// <summary>
/// Methode die einen string im INI-Format einließt
/// </summary>
/// <param name="iniFile">String im INI-Format</param>
public void ReadFile(string iniFile)
{
Read(File.ReadAllText(iniFile));
}

/// <summary>
/// Kopie der Datei speichern (Objekt bleibt unberührt)
/// </summary>
/// <param name="file"></param>
/// <returns></returns>
public bool SaveAs(string file)
{
if (fileName == "") return false;
try
{
File.WriteAllLines(fileName, lines.ToArray());
}
catch (IOException ex)
{
throw new IOException("Fehler beim Schreiben der Datei " + fileName, ex);
}
catch (Exception ex)
{
throw new IOException("Fehler beim Schreiben der Datei " + fileName, ex);
}
return true;
}

/// <summary>
/// Datei speichern
/// </summary>
/// <returns></returns>
public bool Save()
{
return SaveAs(fileName);
}

/// <summary>
/// Datei unter anderem Namen speichern
/// </summary>
/// <param name="file"></param>
/// <returns></returns>
public bool Save(string file)
{
fileName = file;
return SaveAs(fileName);
}

/// <summary>
/// Sucht die Zeilennummer (nullbasiert)
/// eines gewünschten Eintrages
/// </summary>
/// <param name="Caption">Name des Bereiches</param>
/// <param name="CaseSensitive">true = Gross-/Kleinschreibung beachten</param>
/// <returns>Nummer der Zeile, sonst -1</returns>
public int GetCaptionLine(string Caption, bool CaseSensitive)
{
if (!CaseSensitive) Caption = Caption.ToLower();
for (int i = 0; i < lines.Count; i++)
{
string line = lines[i].Trim();
if (line == "") continue;
if (!CaseSensitive) line = line.ToLower();
// Erst den gewünschten Abschnitt suchen
if (line == "[" + Caption + "]")
return i;
}
return -1;// Bereich nicht gefunden
}

/// <summary>
/// Prüft ob ein Bereich existiert.
/// </summary>
/// <param name="Caption">Name des Bereiches</param>
/// <param name="CaseSensitive">true = Gross-/Kleinschreibung beachten</param>
/// <returns>True wenn der Breich existiert, sonst false</returns>
public bool CaptionExist(string Caption, bool CaseSensitive)
{
return GetCaptionLine(Caption, CaseSensitive) != -1;
}

/// <summary>
/// Sucht die Zeilennummer (nullbasiert)
/// eines gewünschten Eintrages
/// </summary>
/// <param name="Caption">Name des Bereiches</param>
/// <param name="Entry">Name des Eintrages</param>
/// <param name="CaseSensitive">true = Gross-/Kleinschreibung beachten</param>
/// <returns>Nummer der Zeile, sonst -1</returns>
public int GetEntryLine(string Caption, string Entry, bool CaseSensitive)
{
Caption = Caption.ToLower();
if (!CaseSensitive) Entry = Entry.ToLower();
int CaptionStart = GetCaptionLine(Caption, false);
if (CaptionStart < 0) return -1;
for (int i = CaptionStart + 1; i < lines.Count; i++)
{
string line = lines[i].Trim();
if (line == "") continue;
if (!CaseSensitive) line = line.ToLower();
if (line.StartsWith("["))
return -1;// Ende, wenn der nächste Abschnitt beginnt
if (Regex.IsMatch(line, @"^[ \t]*[" + CommentCharacters + "]"))
continue; // Kommentar
if (line.StartsWith(Entry + "="))
return i;// Eintrag gefunden
}
return -1;// Eintrag nicht gefunden
}

/// <summary>
/// Prüft ob ein Eintrag existiert.
/// </summary>
/// <param name="Caption">Name des Bereiches in dem gesucht werden soll</param>
/// <param name="Entry">Name des Eintrag der gesucht werden soll</param>
/// <param name="CaseSensitive">true = Gross-/Kleinschreibung beachten</param>
/// <returns>True wenn der Eintrag existiert, sonst false</returns>
public bool EntryExist(string Caption, string Entry, bool CaseSensitive)
{
return GetCaptionLine(Caption, CaseSensitive) != -1;
}

/// <summary>
/// Kommentiert einen Wert aus
/// </summary>
/// <param name="Caption">Name des Bereiches</param>
/// <param name="Entry">Name des Eintrages</param>
/// <param name="CaseSensitive">true = Gross-/Kleinschreibung beachten</param>
/// <returns>true = Eintrag gefunden und auskommentiert</returns>
public bool commentValue(string Caption, string Entry, bool CaseSensitive)
{
int line = GetEntryLine(Caption, Entry, CaseSensitive);
if (line < 0)
return false;
lines[line] = CommentCharacters[0] + lines[line];
return true;
}

/// <summary>
/// Löscht einen Wert
/// </summary>
/// <param name="Caption">Name des Bereiches</param>
/// <param name="Entry">Name des Eintrages</param>
/// <param name="CaseSensitive">true = Gross-/Kleinschreibung beachten</param>
/// <returns>true = Eintrag gefunden und gelöscht</returns>
public bool deleteValue(string Caption, string Entry, bool CaseSensitive)
{
int line = GetEntryLine(Caption, Entry, CaseSensitive);
if (line < 0)
return false;
lines.RemoveAt(line);
return true;
}

/// <summary>
/// Liest den Wert eines Eintrages aus
/// </summary>
/// <param name="Caption">Name des Bereiches</param>
/// <param name="Entry">Name des Eintrages</param>
/// <param name="CaseSensitive">true = Gross-/Kleinschreibung beachten</param>
/// <returns>Wert des Eintrags oder leer</returns>
public string getValue(string Caption, string Entry, bool CaseSensitive)
{
int line = GetEntryLine(Caption, Entry, CaseSensitive);
if (line < 0)
return "";
int pos = lines[line].IndexOf("=");
if (pos < 0)
return "";
return lines[line].Substring(pos + 1).Trim();
// Evtl. noch abschliessende Kommentarbereiche entfernen
}

/// <summary>
/// Liest den Wert eines Eintrages aus
/// Ignoriert Gross-/Kleinschreibung
/// </summary>
/// <param name="Caption">Name des Bereiches</param>
/// <param name="Entry">Name des Eintrages</param>
/// <returns>Wert des Eintrags oder leer</returns>
public string getValue(string Caption, string Entry)
{
return getValue(Caption, Entry, false);
}

/// <summary>
/// Setzt einen Wert in einem Bereich. Wenn der Wert
/// (und der Bereich) noch nicht existiert, werden die
/// entsprechenden Einträge erstellt.
/// </summary>
/// <param name="Caption">Name des Bereichs</param>
/// <param name="Entry">name des Eintrags</param>
/// <param name="Value">Wert des Eintrags</param>
/// <param name="CaseSensitive">true = Gross-/Kleinschreibung beachten</param>
/// <returns>true = Eintrag erfolgreich gesetzt</returns>
public bool setValue(string Caption, string Entry, string Value, bool CaseSensitive, bool SearchComments)
{
Caption = Caption.ToLower();
if (!CaseSensitive)
Entry = Entry.ToLower();
int lastCommentedFound = -1;
int CaptionStart = GetCaptionLine(Caption, false);
if (CaptionStart < 0)
{
lines.Add("[" + Caption + "]");
lines.Add(Entry + "=" + Value);
return true;
}
int EntryLine = GetEntryLine(Caption, Entry, CaseSensitive);
for (int i = CaptionStart + 1; i < lines.Count; i++)
{
string line = lines[i].Trim();
if (!CaseSensitive)
line = line.ToLower();
if (line == "")
continue;
// Ende, wenn der nächste Abschnitt beginnt
if (line.StartsWith("["))
{
lines.Insert(i, Entry + "=" + Value);
return true;
}
// Suche aukommentierte, aber gesuchte Einträge,
// falls der Eintrag noch nicht existiert.
if (SearchComments && EntryLine < 0 && Regex.IsMatch(line, @"^[ \t]*[" + CommentCharacters + "]"))
{
string tmpLine = line.Substring(1).Trim();
if (tmpLine.StartsWith(Entry))
{
// Werte vergleichen, wenn gleich,
// nur Kommentarzeichen löschen
int pos = tmpLine.IndexOf("=");
if (pos > 0)
{
if (Value == tmpLine.Substring(pos + 1).Trim())
{
lines[i] = tmpLine;
return true;
}
}
lastCommentedFound = i;
}
continue;// Kommentar
}
if (line.StartsWith(Entry))
{
lines[i] = Entry + "=" + Value;
return true;
}
}
if (lastCommentedFound > 0)
lines.Insert(lastCommentedFound + 1, Entry + "=" + Value);
else
lines.Insert(CaptionStart + 1, Entry + "=" + Value);
return true;
}

/// <summary>
/// Setzt einen Wert in einem Bereich. Wenn der Wert
/// (und der Bereich) noch nicht existiert, werden die
/// entsprechenden Einträge erstellt.
/// </summary>
/// <param name="Caption">Name des Bereichs</param>
/// <param name="Entry">Name des Eintrags</param>
/// <param name="Value">Wert des Eintrags</param>
/// <param name="CaseSensitive">true = Gross-/Kleinschreibung beachten</param>
/// <returns>true = Eintrag erfolgreich gesetzt</returns>
public bool setValue(string Caption, string Entry, string Value)
{
return setValue(Caption, Entry, Value, false, false);
}

/// <summary>
/// Liest alle Einträge uns deren Werte eines Bereiches aus
/// </summary>
/// <param name="Caption">Name des Bereichs</param>
/// <param name="CaseSensitive">true = Gross-/Kleinschreibung beachten</param>
/// <returns>Sortierte Liste mit Einträgen und Werten</returns>
public SortedList<string, string> getCaption(string Caption, bool caseSensitive)
{
SortedList<string, string> result = new SortedList<string, string>();
bool CaptionFound = false;
for (int i = 0; i < lines.Count; i++)
{
string line = lines[i].Trim();
if (line == "")
continue;

if (caseSensitive)
Caption.ToLower();

// Erst den gewünschten Abschnitt suchen
if (!CaptionFound)
{
if (caseSensitive)
line.ToLower();

if (line != "[" + Caption + "]")
{
continue;
}
else
{
CaptionFound = true;
continue;
}
}

if (line.StartsWith("[")) // Ende, wenn der nächste Abschnitt beginnt
break;
if (Regex.IsMatch(line, @"^[ \t]*[" + CommentCharacters + "]")) // Kommentar
continue;
int pos = line.IndexOf("=");
if (pos < 0)
result.Add(line, "");
else
result.Add(line.Substring(0, pos).Trim(), line.Substring(pos + 1).Trim());
}
return result;
}

/// <summary>
/// Liest alle Einträge uns deren Werte eines Bereiches aus.
/// Ignoriert Gross-/Kleinschreibung
/// </summary>
/// <param name="Caption">Name des Bereichs</param>
/// <param name="CaseSensitive">true = Gross-/Kleinschreibung beachten</param>
/// <returns>Sortierte Liste mit Eintr�gen und Werten</returns>
public SortedList<string, string> getCaption(string Caption)
{
return getCaption(Caption, false);
}

/// <summary>
/// Erstellt eine Liste aller enthaltenen Bereiche
/// </summary>
/// <returns>Liste mit gefundenen Bereichen</returns>
public List<string> getAllCaptions()
{
List<string> result = new List<string>();
for (int i = 0; i < lines.Count; i++)
{
string line = lines[i];
Match mCaption = regCaption.Match(lines[i]);
if (mCaption.Success)
result.Add(mCaption.Groups["caption"].Value.Trim());
}
return result;
}

/// <summary>
/// Exportiert sämtliche Bereiche und deren Werte in ein XML-Dokument
/// </summary>
/// <returns>XML-Dokument</returns>
public XmlDocument exportToXml()
{
XmlDocument doc = new XmlDocument();
XmlElement root = null;

root = doc.CreateElement(Path.GetFileNameWithoutExtension(this.fileName));

doc.AppendChild(root);
XmlElement Caption = null;

for (int i = 0; i < lines.Count; i++)
{
Match mEntry = regEntry.Match(lines[i]);
Match mCaption = regCaption.Match(lines[i]);
if (mCaption.Success)
{
Caption = doc.CreateElement(mCaption.Groups["caption"].Value.Trim());
root.AppendChild(Caption);
continue;
}

if (mEntry.Success)
{
XmlElement xe = doc.CreateElement(mEntry.Groups["entry"].Value.Trim());
xe.InnerXml = mEntry.Groups["value"].Value.Trim();
if (Caption == null)
root.AppendChild(xe);
else
Caption.AppendChild(xe);
}
}
return doc;
}
}
}


Vielleicht kannst du ja was mit anfangen.

ciao Phil

DocEW
2011-01-17, 13:15:49
Die Settings werden jetzt zwar gespeichert (dank an PatkIllA), aber ich sehe noch nicht, wo ich diese dann ausserhalb der Applikation verändern könnte. Denn das wäre eigentlich das Ziel, dass ich in einem externen File ganz einfach ein paar Parameter verändern kann. Die app.config behält ja die Default-Werte...
Die app.config ist nur so eine Art Schablone und wird beim Kompilieren kopiert, z.B. nach bin\Release\MeinProgramm.exe.config. Da kannst du dann Sachen drin ändern.

AwesomeSauce
2011-01-17, 20:05:36
Ich danke allen für eure Hilfe :up:

Bevor ich selbst eine Ini-Klasse schreibe, benutze ich einfach eine sehr(!) rudimentäre Implementierung einer eben solchen.

public class IniFile
{
[DllImport("kernel32")]
private static extern long WritePrivateProfileString(string section,
string key, string val, string filePath);

[DllImport("kernel32")]
private static extern int GetPrivateProfileString(string section,
string key, string def, StringBuilder retVal,
int size, string filePath);

public static void WriteValue(string Section, string Key, string Value)
{
WritePrivateProfileString(Section, Key, Value, Environment.CurrentDirectory.ToString() + "/settings.ini");
}

public static string ReadValue(string Section, string Key)
{
StringBuilder temp = new StringBuilder(255);
int i = GetPrivateProfileString(Section, Key, "", temp, 255, Environment.CurrentDirectory.ToString() + "/settings.ini");
return temp.ToString();
}
}


Für den Moment reicht es. Später wird natürlich eher etwas im Rahmen des Beispiels von -tk|doc implementiert werden.

Danke nochmals!:)

Gnafoo
2011-01-17, 22:06:57
Worin besteht denn das Problem mit dem bestehenden .NET Config-Mechanismus? Der funktioniert doch wunderbar und viel einfacher als Property verwenden uns ggf. Save aufrufen geht es ja kaum.

Klar die Daten landen unter C:\Users\[User]\AppData\Local, aber da gehören sie ja auch hin. Editieren mit dem Editor geht dank XML eigentlich auch problemlos.

Monger
2011-01-17, 22:09:41
Darf ich nochmal fragen, was genau eigentlich die Anforderungen sind, und warum es Probleme mit den .NET-eigenen Settings Dateien gibt?

Eigentlich finde ich das hauseigene Verfahren mit den Config Dateien enorm simpel. Das hat sich eigentlich auch durchgesetzt, INI Dateien sind eigentlich mittlerweile (aus gutem Grund) ziemlich ausgestorben.

Edit: Mist, ein bißchen zu spät! :D

RattuS
2011-01-18, 21:11:21
Ein weiterer Vorteil ist das DataBinding/ApplicationSettingsBinding.

Gast
2011-01-21, 09:03:32
Kann man das irgendwo einstellen das für Release und Debug-Version nur eine Konfigurationsdatei genutzt wird?

Elemental
2011-01-21, 09:14:33
Ich schreibe bzw. lese immer selber eine XML-Datei unter %APPDATA%\Programmname


public void LoadSettings()
{
string strDirectory = GetSettingsFolder();

//check if directory exists
if (System.IO.Directory.Exists(strDirectory) == true)
{
string strFilePath = System.IO.Path.Combine(strDirectory, m_strSettingsFileName);

//check if file exists
if (System.IO.File.Exists(strFilePath))
{
string fileContents;
using (System.IO.StreamReader sr = new System.IO.StreamReader(strFilePath))
{
fileContents = sr.ReadToEnd();
}

this.FromXml(fileContents);
}
}
}

public void SaveSettings()
{
//get the current settings as xml
XmlDocument xmlDoc = this.ToXml();

string strDirectory = GetSettingsFolder();

//check if directory exists
if (System.IO.Directory.Exists(strDirectory) == true)
{
//save the settings
string strFilePath = System.IO.Path.Combine(strDirectory, m_strSettingsFileName);
xmlDoc.Save(strFilePath);
}
}

/// <summary>
/// Gets the path to the folder where settings are saved.
/// If the folder does not exist, the method creates it!
/// </summary>
/// <returns></returns>
private string GetSettingsFolder()
{
string strDirectory = string.Empty;

try
{
strDirectory = System.Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationDat a);
strDirectory = System.IO.Path.Combine(strDirectory, m_strSettingsFolderName);

//check if directory exists
if (System.IO.Directory.Exists(strDirectory) == false)
{
//create the directory
System.IO.DirectoryInfo dirInfo = System.IO.Directory.CreateDirectory(strDirectory);
//dirInfo.Attributes = (dirInfo.Attributes | System.IO.FileAttributes.Hidden);
}
}
catch (Exception ex)
{
this.PostMessage(ex.Message, true);
strDirectory = string.Empty;
}

return strDirectory;
}

DocEW
2011-01-21, 09:53:54
Kann man das irgendwo einstellen das für Release und Debug-Version nur eine Konfigurationsdatei genutzt wird?
Es wird immer die app.config als Vorlage genutzt. Änderungen machst du in VS an dieser Datei. Oder was meinst du? Wenn du die Anwendung auslieferst, nimmst du einfach die Release Version mit der blabla.exe.config.

Monger
2011-01-21, 10:47:44
Ich schreibe bzw. lese immer selber eine XML-Datei unter %APPDATA%\Programmname

Das ist schonmal schlecht, damit bist du nicht Multi-User-fähig. Einstellungen die unbedingt rechnerweit gelten müssen, sind eher selten. In aller Regel hast du eher Einstellungen die benutzerbezogen sind.


Überhaupt: warum sich eigentlich das Leben unnötig schwer machen? Die Windows Forms Settings nehmen einem diesen ganzen Krampf ab. Allein der Code Generator hintendran spart schonmal höllisch viel Schreibarbeit.

PatkIllA
2011-01-21, 11:04:51
Das ist schonmal schlecht, damit bist du nicht Multi-User-fähig.Doch genau damit ist man multiuser tauglich.

Monger
2011-01-21, 11:21:06
Doch genau damit ist man multiuser tauglich.
Sorry, hab das mit ProgramData verwechselt.

Gast
2011-01-23, 12:23:52
Also wenn ich jetzt ein Programm mit folgendem Code habe:


Properties.Settings.Default.Blabla = "test";
Properties.Settings.Default.Save();


Wenn ich das Programm mit F5 starte, also im Debugger, wird die Config im Ordner
ConsoleApplication1.vshos_Url_ut3yushm1im0w03p1exvriyiugm3qesw
gespeichert.
Starte ich über STRG + F5, also ohne Debugger, wird die Config im Ordner
ConsoleApplication1.exe_Url_4l5jtckzmpjjclclvwa5ch3e1boqdgoj
gespeichert.

Also es werden unterschiedliche Konfigurationen benutzt. Und das nervt mich halt. Kann man das ändern das nur eine Config benutzt wird?

Elemental
2011-01-23, 14:58:48
Solche Probleme hatte ich auch, als ich das mit den VS Settings mal ausprobiert hatte. Darum schreibe/lese ich meine settings-datei jetzt immer manuell!

Monger
2011-01-23, 15:27:52
Wenn ich das Programm mit F5 starte, also im Debugger, wird die Config im Ordner
ConsoleApplication1.vshos_Url_ut3yushm1im0w03p1exvriyiugm3qesw
gespeichert.

Darf ich mal fragen, was für ein Visual Studio du verwendest?

Kann mir das aktuell nicht erklären. Wenn man aus VS heraus startet, landet die config normalerweise im dazugehörigen Build Verzeichnis (also Bin\Debug bzw. Bin\Release). Das ganze als Deployment Variante (d.h. als fertiges Paket installiert) wird dann in den Appdata Ordner geschrieben, da wo es ja letztendlich auch hingehört.

Elemental
2011-01-23, 15:54:45
Verwechsel nicht die .config mit den Default-Werten mit den aktuell gespeicherten Werten. Soweit ich mich erinnere, wird das dann in so komischen Ordnern gespeichert.

Gnafoo
2011-01-23, 15:59:47
Dieser lustige Quark der im Verzeichnisnamen steht ist der „Evidence Hash“. Ich dachte eigentlich, das tritt nur beim Debuggen auf. Scheint aber doch nicht so zu sein. Mehr Infos darüber (und zum ganzen System) gibt es hier:

http://blogs.msdn.com/b/rprabhu/archive/2005/06/29/433979.aspx

Es scheint aber nicht allzu schwer zu sein, das Verhalten mit einem eigenen SettingsProvider zu ändern, wenn nötig. Siehe:

http://www.codeproject.com/KB/vb/CustomSettingsProvider.aspx