Eine Solution bauen

Der Titel klingt zugegebenermaßen trivial. Ich habe allerdings immer wieder feststellen müssen, dass vielen auch langjährigen VS-Programmierern gar nicht klar ist, wie eine Solution skalierbar und im Hinblick auf Multi-Tier gebaut werden sollte. Hier ein Vorschlag.

Screencast

Einleitung

Sieht man sich den einen oder anderen Screencast im Netz an, kann schnell der Eindruck entstehen, eine Solution entsteht durch File-New-Project und die Auswahl eines Projektes (meist einer Konsolenanwendung). Für die schnelle Sample-App reicht das sicherlich auch vollkommen aus. Die Frage ist nun, was man eigentlich tun sollte, um eine saubere, für die Zukunft gerüstete und am besten auch für den TFS geeignete Solution zu bauen. Ich werde hier versuchen, eine schrittweise Anleitung zu erstellen, weil ich im täglichen Zusammenarbeiten mit Entwicklern bemerkt habe, dass doch das ein oder andere „Aha!“ vorkommt.

Solution vs. Project

Zunächst einmal gilt es – wie fast immer – ein wenig Trennschärfe in vermeintlich einfache Begriffe zu bringen. Eine Solution ist kein Projekt. Dieser einfache Satz enthält bereits alles wesentliche. Das Problem ist, dass Microsoft hier einiges beim Wording falsch gemacht hat. Um eine Solution zu erstellen, benutzt man nämlich File -> New -> Project.

Gehen wir das einmal durch und machen es ruhig erst einmal falsch. Der folgende Screenshot zeigt, wie ich im Dialog „New Project“ fröhlich auf Console Application gehe und dann nach einer Namensgebung gleich ungehemmt auf „OK“ klicke:

Abb. 1: Falsch gemacht

Das Ergebnis dieses Schnellschusses ist im Solution Explorer:

Abb. 2: 1. Versuch
Abb. 2: 1. Versuch

Das Problem hier ist nun, dass die Solution genau so heißt, wie das Projekt. Die Solution ist aber eigentlich eine Sammlung von beliebig vielen Projekten und i.d.R. entspricht ihr Name eher einer Produktberzeichnung. Würden wir z.B. Microsoft-Entwickler sein, die eine Büro-Anwendungs-Suite erstellen sollen, würde unsere Solution wahrscheinlich „Office“ und eines unserer Projekte z.B. „Word“ heißen.

Etwas besser

Am unteren Rand in Abb. 1 hätte ich nun im Feld „Solution name“ bereits Rücksicht darauf nehmen können:

Abb. 3: Besser
Abb. 3: Besser

Der Solution-Explorer sieht nun auch schon logicher aus:

Abb. 4: Logischer Aufbau
Abb. 4: Logischer Aufbau

Aha! Alles klar. Beitrag zu Ende? Mitnichten!

Ordnung schaffen

Es hat sich in der Vergangenheit als eher ungünstig erwiesen, Projekte direkt unter die Solution selbst zu hängen. Ein Grund dafür ist, dass selbst vermeintlich kleine Solutions schnell anwachsen können und dann die Übersichtlichkeit im Solution Explorer stark leidet. Auch hilft es einem Entwickler, der zum ersten Mal in ein Projekt gerät merklich, wenn sich die Projekte nicht alle gleichrangig unter der Solution versammeln, sondern noch mindestens eine Schicht aus sog. Solution Foldern genutzt wird.

Kurz gesagt ist es, wie im Dateisystem auch. Teile und herrsche usw. Ich kann nur dringend empfehlen, sich eine Standard-Ordnerstruktur als Konvention zu überlegen. Über die Jahre hat es sich für mich und mein Team als erfolgreich erwiesen, die Solution Folder nach den Schichten der Anwendung zu benennen. Folgende Ordner haben wir eigentlich immer am Start:

  • _Shared: Ein Ordner, der immer ganz oben hängt (daher das „_“) und alles mögliche aufnimmt, nur keine Projekte (z.B. Textdateien mit Kennwörtern usw.).
  • Data: Hierunter kommen alle SSDT-Projekte (SQL Server Data Tools) und Klassenbibliotheken, die meist EF-Code oder sonstigen Datenzugriffs-Kram enthalten.
  • Logic: Nicht weiter verwunderlich kommen hier meist Klassenbibliotheken (gerne auch Portable) rein, die zentrale Logik bereit stellen.
  • Services: MEist ebstehend aus WCF-Projekten.
  • Test: Alles, was irgendwie nach Testing riecht, kommt hier rein.
  • Ui: Natürlich benötigen wir meist irgendwas visuelles am Anwender. Hier versammeln sich Web-, XAML und z.B. Consolen-Projekte.
  • Setup: Hier kommt in letzter Zeit immer wieder ein Projekt vom Typ WiX zu Einsatz.

Wenn man nun aber diese Regel befolgt, dann hilft der Ansatz aus Abb. 3 nur bedingt weiter, weil man das neue Projekt gleich fröhlich verschieben müsste. Daher hier nun die aus meiner Sicht beste Vorgehensweise.

Die Solution entsteht

Wie oben bereits erwähnt, hat sich MS einen kleinen Wording-Fauxpas erlaubt, wie die Hervorhebungen im folgenden Screenshot zeigen:

Abb. 5: Blanke Solution
Abb. 5: Blanke Solution

Mit unserem neuen Wissen über die Begriffe „Solution“ und „Project“ ist das fast so lustig, wie der berüchtigte Hinweis: „Klicken Sie auf Start, um zu Beenden.“. Naja, man gewöhnt sich dran. Jedenfalls erzeugt ein Klick auf „OK“ nun folgendes Bild im Solution Explorer:

Abb. 6: Solution ohne Ballast
Abb. 6: Solution ohne Ballast

So gefällt mir das schon besser. Ich habe genau das bekommen, was ich im ersten Schritt auch nur wollte. Die Solution als Container für meine Projekte und Dateien steht bereit und nun kann ich in aller Ruhe die Solution-Ordner anlegen.

Nach ein paar mal Rechtsklick auf die Solution und dann „Add -> New Solution Folder“ sieht meine Solution dann so aus:

Abb. 7: Struktur angelegt
Abb. 7: Struktur angelegt

Das Dateisystem

An dieser Stelle wird es höchste Zeit, sich das Ergebnis unseres Tuns mal im Windows Explorer zu vergegenwärtigen:

Abb. 8: Solution vs. Windows Explorer
Abb. 8: Solution vs. Windows Explorer

Ich habe hier einfach mal den Ordner über den Solution Explorer gelegt, um zu zeigen, dass Visual Studio zwar meine Solution artig in einem eigenen Ordner angelegt, in diesem aber keine Unterordner, wie z.B. „_Shared“ oder „Ui“ zu finden sind.

Hier ist wieder wichtig, Begriffe und in diesem Fall Symbole des Studios zu unterscheiden. Was wir angelegt haben, sind „Solution Folder“. Diese werden mit einem „leichteren“ Symbol im Solution Explorer gezeigt, als ihre Vettern, die „Project Folder“. Der wesentliche Unterschied aber ist nun der, dass bei Anlage eines Project Folder immer auch automatisch ein entsprechender Ordner im Dateisystem erzeugt wird. Bei Solution Foldern ist das nicht der Fall. Sie sind als rein logische Ordnungsinstrumente gedacht.

Wer jetzt wissen will, wo denn nun die Information über diese Ordner liegt, der sei auf die in Abb. 8 zu erkennende „*.sln“-Datei verwiesen. Diese beinhaltet alle Solution-weit geltenden Einstellungen und sieht in unserem Fall ca. so aus:

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0.30723.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_Shared", "_Shared", "{877FA3AD-0796-4826-A997-A34C436B2391}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Logic", "Logic", "{E2066926-7F1A-45CB-AEF4-574ED532FC00}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Ui", "Ui", "{587171AD-4E2D-47CF-B3C4-F62A9563A0E2}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{7BC92E6A-E54F-4EA2-A812-259643BF46C1}"
EndProject
Global
 GlobalSection(SolutionProperties) = preSolution
 HideSolutionNode = FALSE
 EndGlobalSection
EndGlobal

In unserem Fall sind vor allem die mit „Project“ beginnenden Zeilen interessant. Ein Solution Folder ist einfach ein spezieller Projekt-Typ innerhalb einer Solution. Diese Stelle – also die sln-Datei – wird übrigens dann immens wichtig, wenn man sich irgendwann mal fragt, wie man 6 Projekte aus dem Ordner „Ui“, die da irgendwie doch nicht mehr rein sollen flugs mal eben in einen anderen Ordner bewegt!

Doch eigentlich wollten wir uns ja dem Dateisystem widmen. Wenn also Solution Folder (in deutschen Versionen übrigens „Projektmappenordner“) rein logisch sind, dann ist mit Abb. 8 ja alles ok, oder?

Viele werden „Ja“ antworten. Ich denke jedoch anders und würde immer empfehlen, manuell die gleiche Ordnerstruktur im Windows Explorer zu erstellen, wie in der Solution auch. Ja, das geht wirklich nur manuell! Dafür habe ich 2 Gründe. Erstens kommt es in laufenden Projekten immer wieder vor, dass man sich durch die Ordnerstruktur im Windows Explorer hangeln muss und irgendwoher eine der Dateien des Projektes (meist aus dem bin-Ordner) braucht. Es hilft dabei ungemein, wenn die Struktur des Dateisystems bereits auf dem obersten Level der der Solution entspricht. Innerhalb der Solution Folder werden die Projekte z.B. alphabetisch sortiert. Hat man aber physisch alle Projekte in einem Ordner liegen, ergibt sich eine ganz andere Sortierung.

Der weit gewichtigere Grund für den Extra-Schritt ist aber der TFS bzw. überhaupt eine Quellcodeverwaltung. Der Team Foundation Server – wenn er denn genutzt wird – arbeitet bei der Verwaltung des Source Code mit einem Mix aus Solution- und Dateisystem-Logik. Ist beides nicht zueinander konsistent, kann es zu verwirrenden Ergebnissen kommen. Ein Beispiel hierfür sind Berechtigungen. Ohne zu sehr ins Detail gehen zu wollen, hier ein kleines Beispiel. Es kommt ein UI-Entwickler an Bord, der in der Middleware und den anderen Layern außer UI nix verloren hat. Ein Solution Folder ist ein prima Einstiegspunkt, um ihm den Zugriff auf einen Solution Folder zu verwehren. Geht bloß nicht, weil der TFS Solution Folder gar nicht sieht. Hat man keinen entsprechenden Ordner im Dateisystem, sieht der TFS absolut keine Struktur auf Solution Folder Ebene.

Nach meinen Anpassungen im Windows Explorer verwandelt sich Abb. 8 in:

Abb. 9: Dateisystem fertig
Abb. 9: Dateisystem fertig

An dieser Stelle sei noch ein Hinweis auf die versteckte „.suo“-Datei erlaubt. Hier handelt es sich um eine Binärdatei, die eine Art lokalen Cache für die Solution darstellt. Wenn man heftige Änderungen an seiner Projektstruktur vornimmt (z.B., weil man in einer alten Solution aufräumen will), sollte man öfter mal diese Datei löschen und dann das VS inkl. Projekt neu laden. Das hilft Wunder gegen einen Haufen unlogisch erscheinender Fehler.

Die vermaledeite AssemblyInfo.cs

Noch haben wir kein einziges Projekt in der Solution. Trotzdem gehe ich bereits jetzt auf ein weithin bekanntes Problem großer Solutions ein. Eine Standard-AssenblyInfo-Datei sieht wie folgt aus:

using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("ConsoleApplication1")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ConsoleApplication1")]
[assembly: AssemblyCopyright("Copyright © 2014")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("a5842883-d212-497b-acc0-3343534be465")]

// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

Eine erste Verschlankungsmaßnahme entfernt ComVisible, AssemblyCulture, Guid alle Kommentare und überflüssigen Leerzeilen sowie usings:

using System.Reflection;

[assembly: AssemblyTitle("ConsoleApplication1")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ConsoleApplication1")]
[assembly: AssemblyCopyright("Copyright © 2014")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("1.0.0.0")]

Sieht man sich das jetzt einmal genauer an, so würden in einer Solution für ein Produkt eigentlich nur noch die Elemente Zeilen 3 und 4 aus Listing 3 übrig bleiben. Der Rest der Zeilen ist in so einem Fall für die ganze Solution gleich. Diese Aussage hängt nun natürlich auch noch davon ab, wie die Versionierung innerhalb der Projekte erfolgen soll und könnte ganze Blog-Serien füllen. Wer mir aber nun zustimmt, würde sich doch wünschen, dass diese redundanten Teile der AssemblyInfo nicht immer mitgeschleppt und – noch schlimmer – getrennt gepflegt werden müssen.

Die gute Nachricht: Es geht. Die schlechte: Es ist umständich. Die mittelgute: Man muss es pro Solution  nur einmal einrichten. Aber eins nach dem anderen.

Der erste Schritt zum Glück besteht darin, eine einfache Textdatei mit dem Namen „SharedAssemblyInfo.cs“ im Windows-Ordner „_Shared“ (oder wie auch immer der Shared-Ordner heißen soll) anzulegen. Da rein kommt der ganze redundante Teil aus Listing 3 und wir geben ein paar sinnvolle Werte an. Also z.B. so:

Abb. 10: SharedAssemblyInfo anlegen
Abb. 10: SharedAssemblyInfo anlegen

Hier gilt es zu beachten, dass die ganze Aktion nicht im Visual Studio durchgeführt wurde! Als nächstes wechseln wir nun ins VS und klicken rechts auf den Solution Folder „_Shared“ dann auf „Add“ und „Existing Item…“. Jetzt in den Ordner „_Shared“ wechseln und die Datei hinzufügen. Das Ergebnis sieht nun so im VS aus:

Abb. 11: SharedAssemblyInfo im Solution Explorer
Abb. 11: SharedAssemblyInfo im Solution Explorer

Nachdem das erledigt ist, kommen wir nun  zu unserem ersten Projekt. Keine Angst: Das Thema AssemblyInfo ist noch nicht abgeschlossen.

Hier ein Beispiel für eine SharedAssemblyInfo zur Übersicht:


using System.Reflection;

[assembly: AssemblyCompany("codingfreaks")]
[assembly: AssemblyProduct("MySolution")]
[assembly: AssemblyCopyright("Copyright © codingfreaks 2014")]
[assembly: AssemblyTrademark("MySolution")]
[assembly: AssemblyVersion("0.0.1.*")]
[assembly: AssemblyInformationalVersion("0.0.1")]

Man beachte, dass ich am Schluss keine FileVersion verwende sondern diese zugunsten der AssemblyInformationalVersion eingetauscht habe (Details bei MSDN) und dann einen * bei der AssemblyVersion am Ende verwende (siehe Abb. 16).

Das erste Projekt

Es wird Zeit, endlich mal was codierbares in der Solution zu bekommen. Mit anderen Worten: Rechtsklick auf den Ordner „Logic“ dann „Add“ und „New Project“. Wichtig hier ist vor allem der Rechtsklick auf den entsprechenden Solution Folder!!!

An dieser Stelle sind nun (wie immer) 2 Dinge extrem wichtig:

  1. Eine Namenskonvention für Projekte.
  2. Die Auswahl des zuvor erstellten Dateisystemsordners (siehe Abb. 12 unten)
Abb. 12: Neues Projekt hinzufügen
Abb. 12: Neues Projekt hinzufügen

Wenn man Punkt 2 vergisst, ist es vorbei mit der schönen Ordnung im Dateisystem und gerade TFS-User werden irre durch die über die gesamte Ordnerstruktur verstreuten Projekte.

Punkt 1 ist vor allem wegen der obligatorischen Wartbarkeit und dieses Artikels wichtig. Wartbarkeit, Übersicht usw. muss ich eigentlich nicht näher erläutern. In meinem Fall werden die Projekte inzwischen mit dem Solution-Folder als Präfix versehen und dann kommt ein möglichst prägnanter Suffix. Im Beispiel ergibt sich also ein zentrales Kernlogik-Projekt der Business-Logic.

Der bereits erwähnte Artikel macht nun darauf aufmerksam, dass es seit VS 2013 keine gute Idee mehr ist, in 2 Solution Foldern den gleichen Projektnamen zu verwenden (also „Core“ unter Logic und unter Services z.B.). So habe ich das halt früher gemacht, weil ich mir dachte, dass der Solution- und Datei-Ordner genügend aussagen. Seit 2013 kommt allerdings dann VS nicht mehr mit Solution-internen Referenzen klar.

Nachdem ich die obsolute „Class1.cs“ aus meiner Klassenbibliothek entfernt habe, sieht mein Solution Explorer so aus:

Abb. 13: Solution Explorer mit 1 Projekt
Abb. 13: Solution Explorer mit 1 Projekt

Zurück zur AssemblyInfo

Natürlich richtet die im Shared-Ordner rumdümpelnde SharedAssemblyInfo noch gar nichts an. Das kommt jetzt. Das komplizierte an der Angelegenheit ist, dass man leider ein paar Schritte machen muss, um VS zu überlisten. Wir wollen die SharedAssemblyInfo nämlich in unser neues Projekt aufnehmen. Das aber nicht irgendwo, sondern neben die AssemblyInfo im Ordner „Properties“. Das wiederum ist aber kein stinknormaler Ordner und verweigert folgerichtig ein einfaches Rechtsklick und dann „Add…“. Die Lösung ist folgende:

  1. Rechtsklick auf das Projekt „Logic.Core“ und dann „Add“ und „Existing Item…“.
  2. Navigieren in den Ordner „_Shared“ und anklicken der „SharedAssemblyInfo.cs“ (KEIN DOPPELKLICK BITTE!)
  3. Wie in Abb. 14 gezeigt nun den kleinen Pfeil neben der „Add“-Schaltfläche wählen und „Add As Link“ anklicken.
Abb. 14: Add As Link für SharedAssemblyInfo
Abb. 14: Add As Link für SharedAssemblyInfo

Das Ergebnis im Solution Explorer ist nun

Abb. 15: Noch nicht ganz
Abb. 15: Noch nicht ganz

Wie der traurige Pfeil anzeigt, befindet sich der Link nun aber leider nicht im Ordner „Properties“. Das kann man nun mit einem beherzten Drag&Drop aber glücklicherweise lösen (zur not den Screencast dazu konsultieren).

Diese Hinzufügen-dann-aber-Verschieben“-Kavalkade kann man sich spätestens ab dem zweiten Projekt schenken. Jetzt kann man nämlich einfach den Link von dem einen Properties-Ordner in den des anderen Projektes kopieren. Man muss nur noch dran denken (auch das am besten im Screencast verdauen).

Der letzte Schritt zu unserem Glück besteht nun noch im Löschen von Ballast aus der eigentlichen AssemblyInfo.cs in Logic.Core. Diese sieht bei mir zum Schluss dann so aus:


using System.Reflection;

[assembly: AssemblyTitle("Logic.Core")]
[assembly: AssemblyDescription("Core logic of my sample project.")]

Wenn ich nun Logic.Core baue und dann in die Eigenschaften der entstehenden DLL im bin-Ordner schaue, habe ich erreicht, was ich wollte:

Abb. 16: Ergebnis der Mühe
Abb. 16: Ergebnis der Mühe

Mit anderen Worten: Wenn ich nun z.B. mein Minor-Release für die gesamte Solution um 1 erhöhen möchte, brauche ich nur noch die SharedAssemblyInfo.cs einmal bearbeiten und gut. Es spielt übrigens dabei keine Rolle, ob man die im „_Shared“-Ordner verwendet oder direkt im Projekt auf den Link doppel klickt, weil es ja nur eine Referenz ist.

nuget

Nuget wird mehr und mehr zu einer meiner Lieblingsbestandteile der VS-Welt. Damit es aber so richtig sauber funz (vor allem im Team), sollte man dafür Sorge tragen, dass jedem Build eine Aktion vorangestellt wird, die sicherstellt, dass alle Pakete auf dem neuesten Stand sind. Das erledigt ein Rechtsklick auf die Solution und Auswahl von „Enable NuGet Package Restore“. Nach einer Sicherheitsabfrage und einem Abschluss-Bestätigungs-Dialog sieht mein Projekt so aus:

Abb. 17: Package Restore eingebunden
Abb. 17: Package Restore eingebunden

Ich werde hier nicht das gesamte Feature erschöpfend behandeln können. Nur so viel: Wir erhalten die Nuget.exe, deren Config sowie die targets für die Integration in den Build-Process. Diese Integration findet nur statt, wenn die entsprechende Option im VS angehakt ist:

Abb. 18: Package Restore beim Build
Abb. 18: Package Restore beim Build

VS kümmert sich dann um die Integration der targets-Datei und dann führt jeder Build zu einem vorherigen Update der in der Solution enthaltenen Pakete (dafür auch die nuget.exe).

Manchmal schlägt dieser Build beim ersten Mal fehl, weil die Paket-Abhängigkeiten nicht in einem Rutsch aufgelöst werden konnten. Ein zweiter Versuch hilft dann Wunder. Das Output-Fenster ist in solchen Fenster übrigens Gold wert.

Am besten gefällt mir an dem ganzen natürlich, dass die nuget-Macher meine Konvention berücksichtigen und dem Solution Folder „.nuget“ auch gleich noch den passenden Dateisystemordner automatisch spendieren. Bravo!

Noch ein Projekt

Der Rest der Geschichte ist nun denkbar trivial. Ein weiteres Projekt unter Tests (Tests.Core) und ein UI-Projekt (Ui.TestConsole) ergänzen meine Solution:

Abb. 19: Projektstruktur
Abb. 19: Projektstruktur

Ich habe in der Abbildung markiert, an welchen Dateien ich jeweils Änderungen vorgenommen habe. Es ist immer das gleiche Vorgehen:

  1. Neues Projekt durch Rechtsklick auf den richtigen Solution Folder hinzufügen.
  2. Beim Hinzufügen darauf achten, dass das Projekt im richtigen Dateisystemordner landet und der Konvention folgend benannt wird.
  3. Link zu SharedAssemblyInfo.cs aus einem bereits bestehenden Properties-Ordner in den neu hinzugefügten kopieren (Drag & Drop).
  4. AssemblyInfo.cs des neuen Projektes anpassen.

Das wars, könnte man denken, aber eine Sache haben wir da noch.

Namespaces

Es erschreckt mich immer wieder, wie wenig Acht die Leute auf ihre Namespaces legen. Microsoft hat dazu ein paar Konventionen, die unserer ganzen bisherigen Arbeit so richtig die Abrundung geben. Vereinfacht ausgedrückt könnte man sagen:

Der Namespace einer Klasse ergibt sich aus einem beliebigen Suffix gefolgt von {SolutionName}.{SolutionFolder}.{ProjectName ohne SolutionFolder-Teil}.{ProjectFolder1}.{ProjectFolderx}.

Hä?, könnte es nun erschallen. Daher ein kleines Beispiel. In Abb. 19 gilt es, der Program.cs des Projektes „Ui.TestConsole“ den korrekten Namespace zu verpassen. Gesetzt den Fall, ich verwende für alle meine Projekte „de.codingfreaks“ als Präfix für Namespaces (was ich tatsächlich tue), dann ergäbe das


namespace de.codingfreaks.MySolution.Ui.TestConsole"

Damit hier nun nichts schief geht, trage ich diesen Standard-Namespace gleich beim Anlegen neuer Projekte in die Eigenschaften ein. Hier ein Beispiel für die Console:

Abb. 20: Projekteigenschaften anpassen
Abb. 20: Projekteigenschaften anpassen

Hat man sich einmal an diesen 5. Schritt zu jedem neuen Projekt gewöhnt, tut es schon fast körperlich weh, ihn weg zu lassen.

Netter Nebeneffekt aus Abb. 20 für alle Tools-Freunde (ich nutze hier z.B. ReSharper). Code-Analyse-Werkzeuge erkennen die Intention und helfen meist mit Automatiken:

Abb. 21: ReSharper hilft
Abb. 21: ReSharper hilft

Auch das sieht man sich besser noch mal im Screencast an. Meine Screenshot-Techniken reichen für Besseres nicht aus.

Die Solution kann mehr

Was auch viele nicht wissen: Ein  Rechtsklick auf die Solution im Solution Explorer und Auswahl von „Properties“ birgt so manche Erleichterung im Umgang mit großen Solutions. Wer z.B. immer schon 2 Consolen auf einmal Starten und Debuggen wollte, der braucht dafür mitnichten 2 geöffnete Studios:

Abb. 22: Mehrere Startprojekte
Abb. 22: Mehrere Startprojekte

Durch „Multiple Startup projects“ kommt man hier einfach zum Ziel. Auch das Überprüfen und Verwalten der viel gehassten Configurations wird vereinfacht:

Abb. 23: Solution-weite Configuration-Wartung
Abb. 23: Solution-weite Configuration-Wartung

Unvernünftige Klick-Orgien durch alle Projekte können hier schonmal entfallen.

Fazit

So alltäglich der Begriff Solution auch ist, oftmals hat man gerade wegen der scheinbaren Einfachheit des Konzeptes kaum Muße und Lust, sich damit auseinander zu setzen. Ich hoffe, dieser Exkurs konnte das zeigen und sorgt für weniger Frust im Umgang mit den Tools.

 

 

12 Antworten auf „Eine Solution bauen“

  1. Hallo Sprinter,

    danke, danke, danke für den Beitrag und das Video. Das ist genau das was ich gesucht habe. Ich, als Anfänger, habe mich die ganze Zeit gefragt wie ich ein größeres Projekt strukturieren soll.
    Das Thema Solution/Projekte/Namespaces ist mir jetzt um einiges klarer geworden.

    Gruß Erich

  2. Hallo Sprinter

    Dein Beitrag ist super :)
    Die Vorgehensweise zur Strukturierung eines „Programmes“ bzw. der Solution, würde ich gerne für meine zukünftigen Projekte in ähnlicher Form übernehmen. Leider hänge ich daran, diese Struktur und die Aufrufe zwischen den Projekten zu übernehmen. Ich habe z.B. ein Programm mit folgenden Aufbau: Ui(Ein WinForm Projekt mit DataGridView einem Button zum Aktualisieren und einem Label mit Anzahl Zeilen des GDV. Im DGV werden zwei Spalten mit Werten angezeigt, die sich ändern lassen können.), Data (Ein Projekt mit DataSet und enthaltener Tabelle. Im DS werden die angezeigten Werte gespeichert und lassen sich aus einer CSV Datei laden.), Logic (Ein Projekt mit der Main Routine. Wenn der Button geklickt wird, soll die Tabelle im DS von der CSV gefüllt werden. Änderungen an der Anzeige sollen an das DS weitergeleitet und in der CSV gespeichert werden.)

    Wie baue ich sowas auf? Kannst du dazu so eine Beispielsolution Online stellen. Im Internet habe ich bis jetzt immer nur Konsolen-Beispiele gefunden und die sind so simpel gehalten, dass sie nicht praktisch übertragbar sind. Auch dein GOF Beispiel basiert auf einer Konsolen-Lösung und scheint, da schon etwas älter, nicht direkt zu dem aktuellen Solutionaufbau zu passen.
    Ich würde mich sehr freuen, wenn du dazu einen Einstieg Online stellen könntest. Vermutlich stehen andere auch vor diesem Problem.

    Vielen Dank
    Cornelius

  3. Hallo Sprinter,

    super verständlich erklärt, da kommt kein Buch hinterher (betrifft auch die Beiträge zum Thema „WPF und MVVM richtig einsetzen“)!
    In der Hoffnung, dass du immer noch aktiv bist:
    Existiert auch so eine saubere Erklärung für ASP.NET + MVC (Solution anlegen usw.)?

    Viele Grüße
    Peter

    1. Hallo Peter! Danke fürs Feedback. Ich hatte letztens eher immer weniger Zeit zum bloggen und daher gibt es noch so einige Lücken zu füllen. Die Frage wäre heute, ob man sowas noch für ASP.NET oder eher für .NET Core macht. Ich überlege mir etwas.

  4. Wirklich gut. Hätte ich diesen Artikel vor zwei Jahren gelesen hätte ich mir viel Frust und Arbeit gespart….
    Danke für seine Arbeit. :-)

    Gruß
    Kai

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

This site uses Akismet to reduce spam. Learn how your comment data is processed.