Typsichere Anwendungs-Einstellungen in app.config schreiben  
Frank Dzaebel, erstellt am: 3.4.2010, zuletzt geändert:  3.4.2010
Kategorie: Einstellungen, .NET-Version: 3.5/4.0, [Download]

Anwendungs-Einstellungen (im Gegensatz zu Benutzer-Einstellungen) sind standardmäßig (zu Recht) nicht beschreibbar. Tatsächlich gibt es Szenarien, in denen soetwas trotzdem mit Einschränkung sinnvoll sein kann. Insbesondere dann, wenn (etwa kurz nach dem Setup) administrative Rechte vorausgesetzt werden können. Eine .NET gestützte wenig aufwendige Möglichkeit dazu wird im Folgenden vorgestellt.

Typsichere Einstellungen schreiben. (hier: MeinAppFont-Setting)
Beachten Sie: die "app.config" wird zur Entwicklungszeit beim Kompilieren in das Ausführungverzeichnis als "<ApplikationsName>.exe.config" kopiert. Etwa:  [...]/bin/Debug/<AppName>.exe.config. Bei Visual Studio ist standardmäßig der Visual Studio Host-Prozess aktiviert, sodass diese Datei während des Debuggens zum Beispiel folgendermassen heisst: [...]/bin/Debug/<AppName>.vshost.exe.config.
In die "app.config" kann ein Standardbenutzer zur Ausführungszeit (auch unter XP) normalerweise nicht schreiben, da er die Rechte dazu nicht hat, denn diese liegt - wenn sie beim Empfänger installiert ist - im Programme-Verzeichnis! Man würde also administrative Rechte für soetwas benötigen, was dem "best practice" Prinzip von "Least Privilege" nur dann widersprechen würde, wenn die Anwendung standardmäßig mit solchen Admin-Rechten ausgeführt werden müßte, obwohl dies ansonsten nicht nötig wäre.
Die "user.config" ist zur Entwicklungszeit zunächst noch nicht existent! Die "user.config" wird erst erzeugt, wenn den typsicheren Properties ein Wert ungleich dem Vorherigen zugewiesen wird und dann die Save-Methode der Settings aufgerufen wird! Die "user.config" liegt in einem Verzeichnis, wo der Standardbenutzer ändern darf.
Siehe auch: [
Architektur der Anwendungseinstellungen], [Typsichere Settings mit eigenen Array-Typen]

public partial class Form1 : Form
{
  // Verweis hinzufügen: .NET/System.Configuration
  Configuration config;
  ConfigurationSectionGroup appSectionGroup;
  ClientSettingsSection appSection;
  LocalFileSettingsProvider lfp;

  /// <summary>Globale Einstellungen der Applikation</summary>
  Properties.Settings Props = Properties.Settings.Default;

  public Form1()
  {
    InitializeComponent();
    MessageBox.Show("vorher: " + Props.MeinAppFont.ToString()); //Font: 12

    SetzeApplicationSetting(()=>Props.MeinAppFont   , new Font("Arial", 14));
    SetzeApplicationSetting(()=>Props.MeinAppSetting, "Ein neuer Wert !**!");

    MessageBox.Show("danach: " + Props.MeinAppFont.ToString()); //Font: 14
    AnzeigeDerAppConfig();
  }

  private void AnzeigeDerAppConfig()
  {
    if (config == null)
      config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
    Process.Start("notepad", config.FilePath);
  }

  /// <summary>Setzt den Wert der ApplicationSettings-Einstellung 
  /// '<paramref name="appSetting"/>' neu auf: '<paramref name="neuerWert"/>'.</summary>
  /// <param name="appSetting">Anwendungs-Einstellung. Zum Beispiel: ()=>Props.MeinAppSetting</param>
  /// <param name="neuerWert">Neuer Wert der Einstellung.</param>
  void SetzeApplicationSetting<T>(Expression<Func<T>> appSetting, T neuerWert)
  {
    try
    {
      string appSettingName = VariablenName(appSetting);
      if (config == null)
      {
        config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
        appSectionGroup = config.GetSectionGroup("applicationSettings");
        var appSecName = appSectionGroup.Sections[0].SectionInformation.Name;
        appSection = config.GetSection(appSectionGroup.Name +
          "/" + appSecName) as ClientSettingsSection;
        lfp = Props.Providers["LocalFileSettingsProvider"] as LocalFileSettingsProvider;
      }
      SettingElement appSectionElement = appSection.Settings.Get(appSettingName);
      Props.PropertyValues[appSettingName].PropertyValue = neuerWert;
      lfp.SetPropertyValues(Props.Context, Props.PropertyValues);
      appSectionElement.Value.ValueXml.InnerXml =
        Props.PropertyValues[appSettingName].SerializedValue.ToString();
      config.Save(ConfigurationSaveMode.Modified, true);
      ConfigurationManager.RefreshSection(appSection.SectionInformation.SectionName);
    }
    catch (Exception exp)
    {
      MessageBox.Show("Das Setzen von Anwendungs-Settings " +
        "muss mit administrativen Rechten erfolgen!\r\n" +
        "-------------\r\n" + exp.Message);
    }
  }

  /// <summary>Gibt den Namen der Variablen '<paramref name="ausdruck"/>' zurück.</summary>
  /// <param name="expr">Lamda-Ausdruck. Zum Beispiel: 
  ///    ()=>Props.MeinAppFont     ergibt: "MeinAppFont".</param>
  static string VariablenName<T>(Expression<Func<T>> ausdruck)
  {
    var body = ((MemberExpression)ausdruck.Body);
    return body.Member.Name;
  }
}