Standardwerte aus meiner App.config abrufen / setzen

208212
Jamal

Stellen Sie sich vor, ich brauche eine Farbpalette, damit meine Winforms-Anwendung ein einheitliches Erscheinungsbild hat.

Was ich getan habe, war die Erstellung einer statischen Hilfsklasse und Hilfsmethoden, die ich von überall in meinem Code aufrufen kann und das, was ich aus der App.settingsDatei benötige, aufrufen kann.

Hier zum Beispiel bekomme ich den Schulnamen aus der App.configDatei, so dass ich diese Anwendung mit minimalen Änderungen an anderen Schulen verkaufen kann.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="schoolName" value="Uboldi"/>
  </appSettings>
</configuration>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;

namespace Uboldi.Helpers
{
    public static class CustomizationHelper
    {
        public static string GetSchoolName()
        {
            return ConfigurationManager.AppSettings["schoolName"];
        }
    }
}

Verwendungszweck:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Uboldi.Helpers;

namespace Uboldi
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
            LoadFormTitle();
        }

        private void LoadFormTitle()
        {
            var schoolName = CustomizationHelper.GetSchoolName();
            this.Text = String.Format("Sistema {0} - Pagina Principal", schoolName);
        }
    }
}

Gibt es krasse Fehler, die ich mit dieser Art von Architektur mache?

Antworten
71

8 Antworten auf die Frage

42
akmad

Sie sind zwar etwas von Ihrer Frage, können aber dennoch hilfreich sein.

Ich würde empfehlen, sich einen benutzerdefinierten ConfigurationSection- Abschnitt anzusehen, in dem Sie komplexere Konfigurationshierarchien definieren können, die stark typisiert sind. Ich finde es viel einfacher, einen benutzerdefinierten Konfigurationsabschnitt zu verwenden, als sich eine Reihe von magischen Strings im appSettings-Element merken zu müssen. Außerdem können Sie festlegen, welche Werte erforderlich sind, welche Werte standardmäßig verwendet werden usw.

Mit einem benutzerdefinierten Konfigurationsabschnitt können Sie einen Konfigurationstyp erstellen, wie z.

public class UboldiConfigurationSection : System.Configuration.ConfigurationSection {
    [ConfigurationProperty("schoolName")]
    public string SchoolName {
        get { return (string)this["schoolName"]; }
        set { this["schoolName"] = value; }
    }
}

Dann laden Sie diesen Konfigurationstyp:

public static class UboldiApplication {
    public static UboldiConfigurationSection Config { get; internal set; }

    public static void Initialize() {
        Config = ConfigurationManager.GetSection("uboldi") as UboldiConfigurationSection;
    }
}

Die app.config würde dann etwa so aussehen:

<configuration>
    <configSections>
        <section name="uboldi" type="Uboldi.UboldiConfigurationSection, Uboldi" />
    </configSections>
    <uboldi schoolName="Fillmore Central" />
</configuration>

Zuletzt verwenden Sie die Konfiguration durch:

public void Test() {    
    //This only needs to be done once, presumably in your Program.Main method
    UboldiApplication.Initialize();

    var name = UboldiApplication.Config.SchoolName;
}

Ein paar Anmerkungen:

  1. Sie müssen auf die System.Configuration-Assembly verweisen, da sie normalerweise nicht standardmäßig in VS referenziert wird.
  2. Der ConfigurationManager.GetSection("uboldi")erwartet den Namen des Abschnitts in der Datei app.config. Sie werden feststellen, dass dies im obigen Beispiel übereinstimmt.
  3. Das section-Element in der Datei app.config verwendet die standardmäßige Konvention für den Typnamen .Net, um den angegebenen Konfigurationsabschnitt zu finden. In diesem Beispiel gehe ich davon aus, dass der UboldiConfigurationSectionTyp der Uboldi-Namespace ist und sich in einer Uboldi-Assembly (DLL oder Exe) befindet.
  4. Sie können Hierarchie hinzufügen, indem Sie ConfigurationElementUnterklassen erstellen und diese als Eigenschaften in Ihrem Konfigurationsabschnitt und Ihren Elementen verwenden.
  5. Der obige Link bezieht sich auf eine Web.config, aber das Gleiche ist in einer app.config-Datei möglich.
10
Adam Lear

Ich denke, das wäre gut. Eine weitere Option wäre, einen zweiten Konstruktor für das Formular zu erstellen und den Titel in zu übergeben:

public class MainForm : Form
{
    public MainForm()
    {
        InitializeComponent();
    }

    public MainForm(string schoolName) : this()
    {
        this.Text = String.Format("Sistema {0} - Pagina Principal", schoolName);
    }
}

Dies kann jedoch nur eine persönliche Präferenz sein.

Sie können auch den hartcodierten Formulartitel in eine Konfigurations- oder Ressourcendatei extrahieren und stattdessen das Formular wie folgt instanziieren:

var titleFormat = ...; // retrieve format from some place
var schoolName = CustomizationHelper.GetSchoolName();
var form = new MainForm() { Text = string.Format(titleFormat, schoolName) };

Die Auszahlung davon hängt davon ab, wie wahrscheinlich es ist, dass sich dies in der Zukunft ändern wird oder ob Sie die Anwendung in andere Sprachen übersetzen möchten.

8
mletterle

Ist der Zweck von CustomizationHelper nur die Beseitigung des ConfigurationManager / AppConfig-Zeugs? Denn sonst würde ich einfach beim ConfigurationManager bleiben.

Je weniger Reifen benötigt werden, um zu verstehen, was los ist, desto besser in meinem Buch. Es sei denn, Sie sehen die Notwendigkeit, SchoolName eines Tages von einer anderen Quelle (z. B. einer Datenbank) abzurufen.

In jedem Fall könnte der Klassenname wahrscheinlich verbessert werden, vielleicht etwas wie "SchoolConfiguration" und die Eigenschaft "Name" oder die Methode "GetName ()".

3
Dan Diplo

Persönlich hätte ich sie eher statisch als statisch gemacht. Nur scheint mit C # natürlicher. Das Konzept einer statischen Hilfsklasse zum Abrufen von Konfigurationswerten ist jedoch eine solide. Dies ist umso nützlicher, wenn Sie Nicht-String-Typen abrufen, da Sie das Casting für die Helfer-Klasse abstrahieren können.

Nur ein Kommentar - wie wäre es mit einer Fehlerbehandlung in der Hilfsklasse, um sicherzustellen, dass die Konfigurationswerte tatsächlich vorhanden sind?

2
greatwolf

Der vorgestellte Code scheint in Ordnung zu sein, es gibt keine offensichtlichen Probleme. CustomizationHelperkönnte jedoch einen besseren Namen verwenden, um anzugeben, was angepasst wird. Wenn dies Teil eines größeren Projekts ist, CustomizationHelperwäre es eine gute Idee, einen Kommentar anzugeben, um anzugeben, welche Klassen verwendet werden sollen.

2
codingoutloud

Ein paar Gedanken:

  • Der Name "CustomizationHelper" ist nicht sehr spezifisch. Wie wäre es mit CustomerBrandingService? Obwohl es "nur" Daten aus einer Konfigurationsdatei abruft, ist dies möglicherweise nicht immer der Fall und es handelt sich immer noch um einen Anwendungsdienst. (Das Benennen von Klassen mit "Helper" ähnelt dem Benennen mit "Manager" - siehe Referenz unten.)

Auch wenn Ihre Frage vernünftig und einfach ist, ist mir nicht klar, welche Entscheidungen Sie daraus treffen werden. Wenn dies beispielsweise die Basis für eine gesamte App ist, schlage ich einige weitere Optionen vor, die Sie berücksichtigen sollten:

  • Warum erstellen Sie 2011 eine WinForm-App? Betrachten Sie WPF oder Silverlight (möglicherweise Silverlight Out-of-Browser "SLOOB").

  • Wenn Sie "WPF" oder "Silverlight" wählen, wird der Titel am häufigsten über Datenbindung über das Model-View-ViewModel-Muster zugewiesen.

Hinweise für weitere Informationen:

1

Ich habe den Konfigurationsabschnitt an zweiter Stelle. Es hat den Vorteil, eine Einstellung nach Bedarf festzulegen und beim Aufruf von GetSection eine Ausnahme auszulösen, anstatt einen Nullwert mit AppSettings [nonexistingKey] zu übergeben.

1

Ich denke, der Abschnitt "appSettings" ist eine ziemlich nette Lösung für etwas so einfaches wie Ihr Beispiel. Ich verwende dies häufig zum Erstellen von Konfigurationsabschnitten, wenn keine Hierarchie erforderlich ist. Ich finde jedoch das folgende Muster hilfreich, um der Verwendung von appSettings Konsistenz zu verleihen, indem einige Eingaben hinzugefügt werden, was die Vorstellung, ob die Einstellung in der .config-Datei erwartet wird, beinhaltet und die Möglichkeit bietet, einen Standardwert anzugeben .

public static class AppSettingsHelper
{
    private static TReturnType LoadAppSetting<TReturnType>(string name, bool required, TReturnType defaultValue)
    {
        // Check for missing settings
        if (!ArrayExt.Contains<string>(ConfigurationManager.AppSettings.AllKeys, name))
        {
            if (required)
                throw new ConfigurationErrorsException(string.Format("Required setting missing: {0}", name));
            else
                return defaultValue;
        }

        // Read the setting and return it
        AppSettingsReader reader = new AppSettingsReader();
        return (TReturnType)reader.GetValue(name, typeof(TReturnType));
    }

    //example boolean property
    public static bool IsSomethingSet
    {
        get
        {
            return ApplicationSettingsHelper.LoadAppSetting<bool>(
                "settingName",
                true,
                false);
        }
    }

    //int property
    public static int SomeCount
    {
        get
        {
            return ApplicationSettingsHelper.LoadAppSetting<int>(
                "someCount",
                true,
                0);
        }
    }
}

Verwenden Sie wie folgt:

if (AppSettingsHelper.IsSomethingSet)
{
    Console.WriteLine(AppSettingsHelper.SomeCount);
}