Frage

Ich habe eine sehr häufige Situation hier. Und seit Jahren finde ich nicht ob das, was ich tue RIGHT von der Industrie standards.Consider ist eine Anwendung, die mit der Datenbank verbunden ist, aber wo die Verbindungszeichenfolge statt in irgendeiner Datei / Einstellung gespeichert wird, als Befehlszeilenparameter übergeben wird beim Start oder die Datenbank zu dem Zeitpunkt durchsucht, um die Anwendung startet.

Nun wird es notwendig, dass die Verbindungszeichenfolge irgendwo im Rahmen der App zu speichern. Gängigste Methode, die ich gesehen habe es getan ist ein Modul oder globale Klasse mit get / set-Methoden, um die Verbindungen Zeichenfolge zu speichern. Eine andere Art, wie ich es tun würde, wird unter Verwendung von Singleton. Entweder Optionen meine DAL können die Verbindungszeichenfolge zugreifen, wenn es benötigt eine GetConnectionString Methode durch.

Gibt es einen besseren Weg, dies zu tun?

Update: Ich habe keine Config-Datei haben und auch wenn ich es täte würde ich die Verbindungszeichenfolge müssen für die gesamte Lebensdauer des Anwendungsinstanz einmal gelesen werden. erarbeiten können Sie auf dem „injizieren sie in irgendwelche Klassen“ Teil

War es hilfreich?

Lösung

Im allgemeinen globalen Zustand, sei es eine globale Klasse oder ein Singleton, soll nach Möglichkeit vermieden werden.

Die ideale Lösung wäre, um Ihre Anwendung aus Config die Verbindungszeichenfolge laden zu haben und inject es in allen Klassen, die es brauchen. Je nach Größe Ihrer Anwendung eines IoC Container wie Einheit oder Schloss Windsor kann helfen, aber sicherlich nicht ein notwendiger Bestandteil der Lösung.

Wenn das nicht möglich ist und Sie stecken Erhaltung der globalen Zustand (wegen der bestehenden Code-Basis oder was auch immer), ich weiß nicht, dass es einen großen Unterschied zwischen den beiden Ansätzen Sie vorgeschlagen haben.

Update: Nur um zu klären, vergessen all die Dinge über IoC Container für jetzt „Inject“ ist nur eine andere Art „als Parameter übergeben in“ zu sagen (entweder an den Konstruktor der Klasse, oder über eine Eigenschaft, oder was auch immer).

Anstatt eine Datenzugriffsklasse mit der Verbindungszeichenfolge fragen (von irgendeiner Art von globalen oder einem Singleton), hat es über den Konstruktor oder eine Eigenschaft übergeben.

Update # 2:. Ich denke, es gibt noch einige Missverständnisse darüber, was dieser Ansatz bringt

Es kommt grundsätzlich nach unten, ob Ihre Datenzugriffsklasse wie folgt aussieht:

public class DataAccessClass
{
    public DataAccessClass()
    {
        _connString = SomeStaticThing.GetConnectionString();
    }
}

oder

public class DataAccessClass
{
    public DataAccessClass(string connString)
    {
        _connString = connString;
    }
}

Diese Artikel (und in der Tat, viele der Artikel in diesem Blog ) in eine Reihe von Gründen, warum die letztere ist besser als die alte (nicht zuletzt, weil die erstere fast unmöglich zu Unit-Test sind).

Ja, in ein Ort es wird einiger statischer Kerl zu haben, verantwortlich zu sein für die Ergreifung der Verbindungszeichenfolge an erster Stelle, aber der Punkt ist, dass Ihre Abhängigkeiten von statischen Methoden darauf beschränkt sind eine Stelle (die Wahrscheinlichkeit, dass Ihre Hauptverfahren im Prozess des Bootstrapping Ihre Anwendung sein wird), anstatt durch die ganze Code-Basis bestreut.

Andere Tipps

es ist schön, so viele kreative Lösungen für eine solche einfache Problem zu sehen; -)

wesentliche Fakten, von OP Frage:

  1. die connect-string auf der Kommandozeile übergeben
  2. viele andere Komponenten müssen möglicherweise den connect-string
  3. verwenden

so, es gibt keinen Weg, um die Verwendung eines statischen Element ; ob es sich um eine globale Variable (hart in .NET zu tun, wirklich, ohne umschließenden Klasse), eine statische Klasse, oder ein Singleton wirklich keine Rolle spielt. Die kürzeste Weg Lösung eine statische Klasse von der Program-Klasse initialisiert werden würde, den die Befehlszeile verarbeitet werden.

Jede andere Lösung würde erfordern nach wie vor statischen Zugriff auf die übergebenen in connect-string , obwohl sie dies hinter einer oder mehreren Schichten Indirektionsebene verstecken kann.

Ich sage nicht, dass Sie nicht wollen, die grundlegende Lösung mit etwas verkleiden schicker, aber es ist nicht notwendig, und es beseitigt nicht die grundsätzlich statisch / globale Natur des connect-string als beschrieben .

Wenn alles, was Sie speichern eine Zeichenfolge ist (möglicherweise zusammen mit einer Reihe von anderen globalen Anwendungseinstellungen), würde ich nur eine statische Klasse mit einem Bündel von Eigenschaften alles, was zu halten. Ein Singleton ist mehr Code und Wartungsarbeiten, aber es ist nicht notwendig Arbeit in diesem Fall, da Ihre Eigenschaften Klasse ist nicht alles tun werden; nur Dinge halten.

Sicher gibt es einen Weg. Zunächst einmal, bekommen bis zu beschleunigen Dependency Injection und ähnliche Techniken, und über Service-Layer denn das ist, was Sie brauchen hier.

Soweit eine Dienstschicht betrifft, Sie irgendeine Art von Configuration Service benötigen, die das Modul sein, die Teile der Anwendung für Konfigurationsinformationen abfragt - Verbindungszeichenfolgen, URIs, etc:

interface IConfigurationService
    string ConnectionString
    bool IntegratedSecurity
    bool EncryptProfiles

Es sollte ziemlich einfach sein, dass es nur eine Instanz von IConfigurationService in Ihrem System ist, aber dies ist mit einem DI-Containern der Wahl erreicht, nicht mit Singleton-Mustern.

Als nächstes werden alle Ihre DAL Dienstleistungen einen Verweis auf die IConfigurationService erhalten:

class FooDal : IFooDal
    IConfigurationService ConfigurationService

, so dass sie jetzt IConfigurationService.ConnectionString habhaft der Verbindungszeichenfolge verwenden können.

Es hängt davon ab.

Beachten Sie, dass ein Singleton:

  • erzwingt, dass genau eine Instanz der Klasse existieren wird, und
  • bietet weltweiten Zugriff

Ein globales liefert nur die globalen Zugriff, sondern übernimmt keine Garantie über die Anzahl der Instanziierungen.

Und die letzte Option, natürlich, ist eine lokale Variable zu verwenden. Das heißt, übergeben Sie die Config-Info um als einen Parameter an den Konstruktor oder wo immer es gebraucht wird.

zwischen den beiden ersten Wahl sollte etwas einfach sein. Ist es eine Katastrophe, wenn zwei Instanzen der Klasse existieren? Ich würde sagen, wahrscheinlich nicht. Ich möchte kann meine eigene Config-Klasse zu liefern separate Optionen auf eine bestimmte Komponente der App instanziiert, oder meine Unit-Tests zu initialisieren.

Es gibt nur wenige Fälle, in denen Sie Notwendigkeit zu garantieren, dass genau eine Instanz existiert. Aus diesem Grunde ist ein global eine bessere Wahl als ein Singleton sein kann.

Die Wahl zwischen lokalen und globalen ist schwieriger. Globaler wandelbarer Zustand ist in der Regel am besten vermieden werden. Immutable Zustand ist weniger ein Problem, und nicht an die gleichen Synchronisations- / Gleichzeitigkeit / Probleme bei der Skalierbarkeit, dass die globalen wandelbarer Zustand führen wird.

Aber oft kann es vorteilhaft sein, es als eine lokale Variable haben Sie an die Komponenten weitergeben um die es brauchen. Dies kann manuell durchgeführt werden, einfach an den Konstruktor eines Objekts vorbei, die DB-Zugriff benötigt, oder es kann zu einem gewissen Grad mit einem IoC-Containern automatisiert werden.

Aber in jedem Fall, wenn es nicht global ist, dann wird Ihr Code wird allgemeineren und mehr tragbar. Wenn es Abhängigkeiten von Klassen und globalen Daten versteckt hat, dass muss gibt es für den Code zu arbeiten, dann kann es nicht leicht in anderen Projekten verwendet werden, oder wenn Sie das gesamte Code-Basis zu viel Umgestalten.

Es wird auch zu Unit-Test härter, wieder, weil der Code nicht selbst kompilieren, wenn einige externen Daten vorhanden ist, dass wir im Idealfall aus unserem Test verlassen mögen.

als @Anton sagte, müssen Sie eine Schnittstelle haben, die so etwas wie

aussetzt
interface IConfigurationService
    string ConnectionString

Dann, wenn einer Ihrer Klasse Verbindungszeichenfolge muss, können Sie es mit einer Implementierung von IConfigurationService auf Konstruktion bieten die gültige Zeichenfolge enthält. Sie benötigen einen gültigen Platz zu finden, Ihre Implementierung zu erstellen, wenn Sie startet App (wahrscheinlich die Zeit, wo Sie Ihre Datenbank-Adresse bekommen), und es zu passieren entlang der Klasse braucht es.

Auch wenn es vielleicht scheint eine Menge Arbeit im Vergleich zu Singletons oder global, wird diese Kopplung in Ihrem Code senkt damit Wiederverwertbarkeit zu verbessern und macht Unit-Tests zu erleichtern, und ist ziemlich einfach, wenn Sie sich selbst davon überzeugen, dass Globals sind (meistens) evil: )

Wie bereits erwähnt, gibt es IoC-Container, die den Rahmen, das zu tun bieten wird, aber es könnte viel des Guten in Ihrem Fall sein, und es ist schön für sich selbst das Muster zu verwenden, bevor das Werk zu einem „Magic Box“ lassen

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top