2012-11-29 4 views
5

Ich habe eine C# WinForms-Anwendung in Visual Studio 2010, die von zwei verschiedenen Kunden verwendet wird. Die grundlegende Funktionalität der Anwendung ist für jeden Kunden gleich, aber bestimmte Codezeilen (Namen von gespeicherten Prozeduren, Ressourcen, bestimmte Verhaltensweisen) unterscheiden sich zwischen den Versionen. Bisher habe ich die Anwendung im selben Projekt beibehalten und beim Erstellen/Veröffentlichen Präprozessordirektiven verwendet, um zwischen der zu verwendenden Bereitstellung zu wechseln. Der Umfang des Projekts ist jedoch soweit angewachsen, dass dies nicht mehr möglich ist.Zwei Versionen einer Anwendung gleichzeitig verwalten und bereitstellen

Da so viel vom Code geteilt wird, versuche ich Quelldateien zu duplizieren. Ich frage mich, welcher Ansatz am besten geeignet ist, um eine Anwendung zu verwalten, die die gleichzeitige Bereitstellung verschiedener Versionen erfordert.

+0

Präprozessordirektiven sollten nicht zur Verarbeitung von Verzweigungen verwendet werden. –

+0

Einverstanden. Dies begann als kleine interne Anwendung, für die externe Kunden Interesse bekundeten. Daher benötigten wir eine schnelle Lösung für die Trennung. – WickerPopstar

Antwort

4

Verwenden Sie Schnittstellen, um Ihre Klassen zu definieren. Eine Schnittstelle zu haben bedeutet, dass Sie mehrere Implementierungen der gleichen Schnittstelle haben können, eine für jeden der Clients. Dazu müssen Sie Ihre vorhandene Codebasis analysieren und logische Trennungen in Ihrem Code identifizieren, in denen diese Schnittstellen definiert werden können.

Sie können dann je nach Bedarf eine Schnittstelle basierend auf dem Client laden. Sie können dies zum Beispiel über die Konfiguration tun. Basierend auf einem Konfigurationswert laden Sie Implementierung1 oder Implementierung2. Es gibt viele, viele Möglichkeiten, dieses spezielle Bit zu erreichen. Sie sollten sich mit der Abhängigkeitsinjektion und der Inversion der Kontrolle befassen und sich Tools wie Ninject, Autofac, Unity ansehen.

Es mag zunächst schwierig sein, zu überlegen, wie Sie Präprozessordirektiven verwenden, aber wenn Sie sehen, wie Ihre Anwendung wächst, werden Sie dieses Refactoring benötigen. Denken Sie daran, wenn Sie es jetzt nicht tun, wird dieses Refactoring später teurer, wenn Ihre Anwendung komplexer wird.

+0

Ich hatte Ahnung, es war ein Architekturproblem, und danke für die Terminologie (Abhängigkeitsinjektion, IOC, etc). Das waren die Begriffe, die mir bei der Suche nach einer Lösung fehlten. – WickerPopstar

2

Die verschiedenen Funktionen sollten Teil der Anwendungsarchitektur sein. Wenn Sie für verschiedene Kunden unterschiedliche Funktionen benötigen, abstrahieren Sie sie - erstellen Sie eine Schnittstelle, die das Verhalten umschließt, und implementieren Sie sie dann auf zwei verschiedene Arten in zwei verschiedenen Assemblys. Dann können Sie (abhängig von Ihrem Bereitstellungsmechanismus) Ihre App entweder mit der einen oder der anderen DLL ausliefern. Um zu vermeiden, dass man neu kompilieren, Referenzen hinzufügen muss, können Sie Dependency-Injection-Frameworks wie Ninject, Castle Windsor, MEF usw. verwenden. Das ist eine "pluginartige" Architektur, wenn der Code ausreichend verschieden ist.

Wenn Sie über Text, Farben, grundlegende Unterschiede sprechen, sollten sie einfach nicht fest codiert, sondern datengesteuert sein. Wenn Ihre App mit dem Internet verbunden ist, könnte sie die entsprechenden Einstellungen herunterladen, wenn sich der Benutzer anmeldet. Andernfalls könnte etwas, das den Text/die Farben/das Verhalten angibt, in eine kundenspezifische Konfigurationsdatei eingegeben werden. Sie können Config-Transformationen verwenden, um diesen Prozess zu vereinfachen.

+0

Die grundlegenden Unterschiede sind glücklicherweise bereits datengetrieben. Es ist hauptsächlich Funktionalität. Ich bin mit diesen Frameworks nicht vertraut, aber diese Anwendung verwendet eine ClickOnce-Bereitstellung. Ändert sich dadurch, wie diese Frameworks implementiert werden? – WickerPopstar

+0

Ich habe genau die gleiche Situation in meinem Projekt. Ninject, andere DI-Frameworks werden funktionieren, aber wir laden DLLs dynamisch von einer URL herunter, nachdem die App installiert wurde: Andernfalls erhält jeder Kunde eine DLL mit der Logik aller anderen Kunden in seiner eigenen Installation. Es ändert sich nicht viel, nur dass Sie Assemblys von einer URL statt von einer Festplatte laden möchten. Oder was du es von Diskette trotzdem machen kannst :) –

0

Sie können möglicherweise einige der Unterschiede trennen, indem Sie Ressourcen-, Konfigurations- oder Eigenschaftsdateien verwenden. Damit meinen Sie, dass Sie in der Datei einen Wert speichern, z. B. den Namen der gespeicherten Prozedur, die in einer bestimmten Situation verwendet werden soll. Dann liest Ihr Code den Namen aus der Datei und führt ihn aus. Sie können die Werte in der Datei ändern, ohne den Code für jede Bereitstellung neu erstellen zu müssen.