Juli 2016
Band 31, Nummer 7
.NET-Grundlagen – Visual Studio 2015 mit .NET Core-Tools
Von Mark Michaelis
.NET Core RC2 ist endlich da, und dieses Mal handelt es sich wirklich um einen echten „Release Candidate“ und nicht um einen RC1 Beta, der so tut, als sei er ein Release Candidate (falls überhaupt, angesichts all der Änderungen, die seit seiner Veröffentlichung erfolgt sind). Der Schwerpunkt für die Entwicklung und in den Medien, was .NET Core angeht, liegt auf seinen plattformübergreifenden Fähigkeiten. Dieser Fokus auf Unterstützung von Linux und Mac OS X hat nicht nur zu einer neuen.NET-API, sondern auch zu einer begleitenden Runtime und sogar einem Toolset geführt. Tools wie DOTNET.EXE (zuvor DNX, DNVM und DNU) und erst recht Visual Studio Code haben allesamt den Zweck, Nicht-Microsoft-Entwicklern die Möglichkeit zu geben, .NET und darüber hinaus eine erstklassige Entwicklungsumgebung zu nutzen.
Das ist alles wirklich ganz toll, doch was ist mit langjährigen Microsoft-Entwicklern? Wie geht ihre Entwicklung unter Windows und Visual Studio mit .NET Core-Projekten weiter? In diesem Artikel stelle ich die verschiedenen .NET Core-Projekttypen vor und erläutere die Details der neuen Dateitypen und ihrer Funktionen. Ich erörtere außerdem, wie die neue Projektstruktur das parallele Debuggen von Open-Source-NuGet-Paketen unterstützt, auf die Sie ggf. verweisen, und Sie den Quellcode solcher Projekte schrittweise ausführen.
Erste Schritte
Bevor Sie anfangen, mit .NET Core RC2 zu arbeiten, müssen Sie zunächst Ihre Tools aktualisieren (in diesem Fall auf Visual Studio 2015), um die neue Plattform zu unterstützen. Dies umfasst im Wesentlichen zwei Schritte:
- Herunterladen von .NET Core Tooling Preview 1 für Visual Studio 2015 von microsoft.com/net/core#windows (dort finden Sie auch Anweisungen).
- Herunterladen und Installieren des NuGet-Paket-Managers von bit.ly/27Rmeaj.
Ich setze voraus, dass Sie Visual Studio 2015 bereits installiert haben. Doch falls nicht, steht Visual Studio Community Edition unter visualstudio.com kostenlos zur Verfügung.
Neue Projekttypen
Nachdem alle Visual Studio-Tools installiert sind, können Sie mit dem Assistenten für neue Projekte Ihr Projekt erstellen (siehe Abbildung 1).
Abbildung 1: Visual Studio .NET Core-Projektvorlagen
Wie Sie sehen, gibt es vier Projekttypen (einer wird zweimal angezeigt, da er sich sowohl im Ordner„ Visual C#\Web“ als auch im Ordner „Visual C#\.NET Core“ befindet).
Wie Abbildung 2 zeigt, generiert jeder Projekttyp eine andere Gruppe von Dateien.
Abbildung 2: Die in jedem Visual Studio-Projekttyp enthaltenen Dateien
Dateiname | Klassenbibliothek | Konsolenanwendung | ASP.NET Core-Webanwendung (.NET Core) | ASP.NET Core-Webanwendung (.NET Framework) |
App.config | X | |||
Properties\AssemblyInfo.cs | X | X | ||
Class1.cs | X | |||
Global.json | X | X | X | X |
Properties\launchSettings.json | X | X | ||
Program.cs | X | X | X | |
Project.json | X | X | X | X |
Project.lock.json | X | X | X | X |
Project_Readme.html | X | X | ||
<Projekt>.xproj | X | X | ||
<Projekt>.xproj.user | X | X | ||
Startup.cs | X | X | ||
Web.config | X | X |
„App.config“ ist eine optionale Konfigurationsdatei vergleichbar mit der bekannten Datei„ <App-Name>.config“, die seit .NET Framework 1.0 im Einsatz ist. Der folgende Code zeigt die Standarddatei, die angibt, ob eine serverbasierte Garbage Collection oder Garbage Collection des Typs „Client/Arbeitsstation“ erfolgen soll (weitere Informationen finden Sie unter bit.ly/22nm32o):
<configuration>
<runtime>
<gcServer enabled="true"/>
</runtime>
</configuration>
„AssemblyInfo.cs“ bestimmt Assemblydaten, wie z. B. Konfiguration, Unternehmen, Produkt und Marke. Dies ist die Standarddatei „AssemblyInfo.cs“, die seit der Erstveröffentlichung von .NET im Jahr 2000 Teil von Visual Studio .NET-Projekten ist.
„Class1.cs“ ist das Skelett einer C#-Klassendatei für die Klasse „Class1“ und enthält deren Standardkonstruktor.
„Global.json“ wird automatisch generiert, solange Sie beim Erstellen Ihres ersten .NET Core-Projekts „Projektmappenverzeichnis erstellen“ auswählen. Im weiteren Verlauf dieses Artikels wird erläutert, wie der Knoten des Projekts beim Debuggen weitere Speicherorte für Quellcode bestimmt.
„LaunchSettings.json“ bestimmt die verschiedenen Konfigurationseinstellungen für das Webhosting. Dazu zählen eine Anwendungs-URL für das Debuggen, ein IIS-Host (z. B. IIS Express), sofern erforderlich, vor dem Start festzulegende Umgebungsvariablen, die beispielsweise von der .NET Core-Konfiguration zum Bestimmen der Umgebung (Entwicklung, Test oder Produktion) verwendet werden, sowie SSL und Authentifizierung. Dank Änderungen an der Registerkarte „Debuggen“ im Visual Studio-Fenster „Projekteigenschaften“ gibt es nun eine Benutzeroberfläche für das Bearbeiten der Datei „launchSettings.json“ (siehe Abbildung 3).
Abbildung 3: Registerkarte „Debuggen“ im Visual Studio-Fenster „Projekteigenschaften“
Abbildung 4 zeigt ein Beispiel der Datei „launchSettings.json“.
Abbildung 4: Beispiel der Datei „launchSettings.json“
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:43799/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"WebApplication1NetFramework": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
„Project.json“ ist eine neue Projektdatei, deren Funktionalität größtenteils mit der der Datei „*.*PROJ“ übereinstimmt. Sie dient zum Angeben von Projektverweisen, Buildoptionen wie der Versionsnummer und der Plattform, für die die Kompilierung erfolgen soll, beispielsweise .NET Core oder .NET Framework. Auf dieses Thema wird in Kürze näher eingegangen.
In „Project.lock.json“ wird eine Liste der Dateien gespeichert (meist NuGet-Verweise), die für die Kompilierung benötigt werden. Dazu gehören bestimmte Paketversionsnummern im Gegensatz zur Datei „project.json“, die Platzhalter unterstützt. Ohne „project.lock.json“ erfolgt eine vollständige Wiederherstellung von Paketen. „Project.lock.json“ enthält ein Paketdiagramm sowie andere Daten im Zusammenhang mit Paketen, die lokal heruntergeladen bzw. wiederhergestellt wurden. Im Allgemeinen ist diese Datei nicht eingecheckt. Sollte sie nicht vorhanden sein, wird sie beim Ausführen einer NuGet-Paketwiederherstellung neu erstellt. Diese Datei ist in Visual Studio als untergeordnete Datei von „project.json“ aufgeführt.
„ClassLibrary.xproj“ ist die MSBuild-Datei, die standardmäßig definiert, was passiert, wenn Sie das Projekt erstellen. Die neueste Version importiert „Microsoft.DotNet.targets“ zum Definieren von Buildaufgaben, die den neuen Befehl „DotNet.exe“ nutzen. Im Gegensatz zu bisherigen MSBuild-PROJ-Dateien sind XPROJ-Dateien überraschend klein, da ein Großteil der Informationen (für den Moment) in „project.json“ verschoben wurde.
„ClassLibrary.xproj.user“ überschreibt die Datei „ClassLibrary.xproj“ und stellt zusätzliche MSBuild-Eigenschaften zur Verfügung, z. B. für den lokalen Benutzer spezifische Einstellungen für das Debuggen wie Ports. Diese Datei wird generell nicht eingecheckt, da sie benutzerspezifisch und in Visual Studio nicht sichtbar ist.
„Program.cs“ definiert eine „Program“-Klasse, die die Definition des Einstiegspunkts „Main“ für Ihre Anwendung enthält (auch für Webanwendungen).
„Web.config“ bietet eine Minimalkonfiguration für IIS, die IIS informiert, wo der Webhostprozess zu finden ist, und konfiguriert, dass sämtlicher Datenverkehr zu diesem Prozess umgeleitet wird (wie im folgenden Code gezeigt):
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<handlers>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule"
resourceType="Unspecified"/>
</handlers>
<aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%"
stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout"
forwardWindowsAuthToken="false"/>
</system.webServer>
</configuration>
Beachten Sie, dass „web.config“ keine App-Einstellungen mehr enthält. Diese wurde in Konfigurationsdateien verschoben, die von „Microsoft.Extensions.Configuration“ geladen werden. Siehe dazu meinen Artikel vom Februar 2016, „.NET-Grundlagen – Konfiguration in .NET Core“ (bit.ly/1OoqmkJ).
Beachten Sie bei allen von Visual Studio erstellten .NET Core-Projekttypen beim Auswählen der Option „Projektmappenverzeichnis erstellen“, dass wenn ein neues Projekt erstellt wird, der gesamte Quellcode in einem Unterverzeichnis des Typs „src“ für die Projektmappe abgelegt wird. Darüber hinaus wird erwartet, dass Testprojekte neben „src“ in einem Verzeichnis namens „test“ abgelegt werden (wenngleich dies in der Version .NET Core Tooling Preview 1 for Visual Studio 2015 nicht standardmäßig erfolgt). Weiter in Betracht zu ziehen, sind Verzeichnisse für Elemente wie Builds und Dokumente. (Ich gebe zu, dass ich meine Testprojekte lieber neben dem getesteten Zielprojekt platziere, anstatt in einer gänzlich getrennten Struktur. Aber das ist nicht das, was Microsoft für die standardmäßige Projektmappenstruktur vorgesehen hat. Und aus Erfahrung weiß ich, dass es ratsam ist, sich an die Standardeinstellungen zu halten, anstatt zu versuchen, dagegen zu kämpfen.)
Weitere Informationen zu „Project.Json“
Die vielleicht wichtigste Datei in der neuen .NET Core-Projektstruktur ist „project.json“. Diese Datei hat folgende Aufgaben:
- Ersetzen der NuGet File Manager-Datei „package.config“, die die NuGet-Verweise für das Projekt bestimmt.
- Angeben der Frameworks, die das Projekt unterstützt, und von Konfigurationsdetails zum Erstellen des Projekts für das jeweilige Framework.
- Bestimmen der Zielplattform für eigenständige Apps, die alle Abhängigkeiten enthalten, einschließlich der plattformspezifischen .NET Core-Runtimes, die für die entsprechende Plattform benötigt werden. Wenn das Projekt eine portierbare App ist, bestimmt „project.json“ die Frameworks, deren Installation das Projekt auf dem Zielcomputer erwartet, auf dem die Assembly ausgeführt wird.
Diese drei Aufgaben sind auf vier Hauptabschnitte innerhalb von „project.json“ aufgeteilt (ich kombiniere je nach Projekttyp die Abschnitte „runtimes“ und „supports“, wenn sich die Funktionalität überschneidet):
Dependencies: In diesem Abschnitt sind die einzelnen NuGet-Pakete aufgelistet, von denen Ihr Projekt abhängt, einschließlich der Versionsnummer besagter Abhängigkeiten. Versionsnummern können mithilfe von Platzhaltern angegeben werden, sodass Sie ermöglichen können, dass die neueste Version, die dem Platzhalter entspricht, von der NuGet-Paket-Manager-Wiederherstellung automatisch heruntergeladen wird. Ein Paar leerer Anführungszeichen für die Versionsnummer bedeutet „Die neueste verfügbare verwenden“. Darüber hinaus können Sie Verweise über das Visual Studio-Fenster „NuGet-Paket-Manager“ hinzufügen und sich auch darauf verlassen, dass Visual Studio asynchron IntelliSense mit den Paketen lädt, die in Ihrer konfigurierten Paketquelle oder einem entsprechenden Feed verfügbar sind (siehe Abbildung 5). IntelliSense funktioniert sowohl für den Paketnamen als auch die Versionsnummer.
Abbildung 5: IntelliSense wird dynamisch mit der Liste verfügbarer Pakete und Versionen geladen
Frameworks: In diesem Abschnitt geben Sie die Frameworks an, in denen Ihr Projekt ausgeführt wird. Beispiele: net45, netstandard1.5, net40. Sie können „buildOptions“, „dependencies“, „frameworkAssemblies“ und „imports“ für das angegebene Framework app-spezifisch angeben. Um beispielsweise unsicheren Code für die Ausführungsumgebung .NET 45 zuzulassen, können Sie im „frameworks“-Element Folgendes angeben:
"net45": {"buildOptions": {"allowUnsafe": true}}
„runtimes/supports“: Ob „project.json“ die Abschnitt „runtimes“ oder „supports“ enthält, hängt davon ab, ob das Projektziel eine portierbare oder eigenständige App ist. Bei eigenständigen Apps gibt der Abschnitt „runtimes“ an, welche Betriebssysteme unterstützt werden und welche Runtimebibliotheken daher in die Anwendung gepackt werden müssen. Eine eigenständige Anwendung hat (zumindest was .NET betrifft) keine Abhängigkeiten von vorinstallierten Elementen auf dem Zielcomputer.
Dagegen gibt der Abschnitt „supports“ für portierbare Apps die Runtime-Abhängigkeiten an, nach denen eine App beim Start sucht, von denen eine ausreichend ist. Die Liste ist nicht restriktiv (eine Ausführung woanders ist ggf. möglich), doch ein „supports“-Element bewirkt, dass NuGet prüft, ob alle Abhängigkeiten erfüllt sind.
Wenngleich die Datei „project.json“ in RC1 und RC2 von besonderer Bedeutung ist, haben die .NET Core- und ASP.NET- Teams nicht lange nach der Veröffentlichung von RC2 bestimmt, dass „project.json“ eigentlich für die bereits umfassend etablierte MSBuild-Projektdatei redundant sei. Diese unterstützt bereits wesentlich mehr Funktionalität, wie z. B. Konfiguration, Buildabhängigkeiten, Buildziele, Kompilierungsflags, Einstellungen für Befehlszeilen- und Umgebungsvariableneigenschaften sowie Buildbefehle. Anstatt all dies neu zu erfinden, prüfte das Team, wodurch die Erstellung der Datei „project.json“ überhaupt ausgelöst wurde, und stellte fest, dass „*.*PROJ“-Dateien im Allgemeinen sehr überfrachtet waren. In ihnen werden alle Dateien in einem Projekt individuell aufgelistet, anstatt z. B. Platzhaltermuster zu verwenden. Die Überfrachtung ist so enorm, dass Entwickler die Datei nur selten öffnen und überprüfen, bevor ein Build ausgeführt wird, selbst wenn die Datei möglicherweise einige darin eingebettete unerwünschte Befehle enthält. Anstatt eine komplett neue Builddatei zu erstellen, entschied sind das Team stattdessen zum Beseitigen der Überfrachtung in „*.*PROJ“-Dateien und außerdem zum Bereitstellen eines Befehlszeilenprogramms zu ihrer Bearbeitung. Das einzige Element, das „project.json“ enthält und „*.*PROJ“-Dateien nicht, ist die JSON-Syntax. (Aber im Grunde genommen ist JSON bloß modernes XML, so wie XML [zu seiner Zeit] das moderne Flatfile- oder INI-Dateiformat war.) Weitere Informationen zum potenziellen „Niedergang“ von „project.json“ finden Sie in der Ankündigung von Damian Edwards beim ASP.NET Community Standup vom 10. Mai 2016 und dazugehörigen Beitrag von Alexandre Mutel (bit.ly/1NJ9r31), sowie in der Zusammenfassung von Willem Meints in seinem Blog (bit.ly/1sJc2An).
Debuggen von Paketquellcode
Eines der Features, das mir am besten gefällt, ist die neue Unterstützung des Debuggens und schrittweisen Ausführens von Paketen und sogar der Änderung des Quellcodes der Pakete, sofern verfügbar. Angenommen, Sie haben eine unternehmensweite „Framework“-Assembly, die von mehreren Teams gemeinsam genutzt wird. Das „Framework“-Paket ist jedoch im Wesentlichen Open Source, weshalb alle im Unternehmen (oder noch besser außerhalb des Unternehmens) Verbesserungen und Änderungen beitragen können. Stellen Sie sich nun vor, dass Sie auf das NuGet-Paket für dieses Framework verweisen. Sie vermuten jedoch an einem bestimmten Punkt, dass ein Fehler vorliegt, der korrigiert werden muss, oder dass eine Verbesserung nötig ist. Normalerweise erfordert dies das Arbeiten mit dem Quellcode der Komponente unabhängig von Ihrem Projekt bzw. Ihrer Projektmappe. Wie wäre es, wenn Sie den Quellcode herunterladen und ihn in einer integrierten Umgebung neben Ihrer Hauptentwicklung aktualisieren und ihn sogar schrittweise durchlaufen könnten, ohne dass ein Symbolserver oder PDB-Dateien verfügbar sein müssen? Zum Glück ist dies in Visual Studio 2015 so möglich.
Angenommen, Sie möchten das Paket „Microsoft.Extensions.Logging“ debuggen, das auf GitHub verfügbar ist. Um es Ihrem Projekt hinzuzufügen und zu debuggen, müssen Sie den Quellcode herunterladen (z. B. mit dem Befehl „git clone“ oder „git submodule“). Damit Visual Studio anschließend weiß, wo der Quellcode zu finden ist, müssen Sie den Projektknoten „global.json“ bearbeiten, indem Sie beispielsweise „submodules\Logging“ der Liste der überwachten Verzeichnisse hinzufügen:
{
"projects": [ "src", "test", "submodules\Logging" ],
"sdk": {
"version": "1.0.0-*"
}
}
Sie können freilich auch den vollständigen Pfad angeben (wenn Sie z. B. den Code nicht in ein Unterverzeichnis geklont haben). Beachten Sie jedoch, dass das Verzeichnistrennzeichen entweder zwei Rückwärtsschrägstriche (\\) oder ein einzelner Schrägstrich ist (Beispiel: c:/users/mark/documents/visual studio2015/Projects/Microsoft.Extensions.Logging).
Sobald Visual Studio den Quellcode findet, nachdem „global.json“ aktualisiert und gespeichert wurde, wird das Projekt automatisch Ihrer Projektmappe so hinzugefügt, dass Sie den Quellcode debuggen können.
Ein relativ einfacher Algorithmus dient zum Bestimmen des Quellcodeverzeichnisses, das geladen werden soll:
- Wenn in „global.json“ angegebene Quellcodeverzeichnisse einen Ordner enthalten, dessen Name mit dem des Pakets identisch ist (Beispiel: Microsoft.Extensions.Logging) und dieser Ordner eine Datei namens „project.json“ enthält, verwendet der Debugger diesen Ordner und die darin enthaltene Datei.
- Andernfalls wird die aus dem Ordner „packages“ kompilierte Binärdatei geladen.
Weitere Informationen finden Sie im Blogbeitrag „Debugging ASP.NET 5 Framework Code Using Visual Studio 2015“ (bit.ly/22niJ7w).
Zusammenfassung
Wenn Sie sich noch nicht mit .NET Core beschäftigt haben, ist nun ein guter Zeitpunkt, sich einen Vorsprung zu verschaffen, um von der langen Lernkurve zu profitieren. Für diejenigen von Ihnen, die ein Upgrade einer früheren Version in Betracht ziehen, gilt dasselbe. Die Wahrscheinlichkeit ist hoch, dass Sie früher oder später sowieso ein Upgrade durchführen. Je eher dies erfolgt, desto schneller kommen Sie in den Genuss der neuen Features.
Mark Michaelis ist der Gründer von IntelliTect und arbeitet als leitender technischer Architekt und Trainer. Seit fast zwei Jahrzehnten ist er ein Microsoft MVP und seit 2007 Microsoft-Regionalleiter. Michaelis arbeitet in verschiedenen Microsoft-Softwareentwicklungs-Reviewteams mit, einschließlich C#, Microsoft Azure, SharePoint und Visual Studio ALM. Er hält häufig Vorträge bei Entwicklerkonferenzen und hat viele Bücher geschrieben, einschließlich seines letzten „Essential C# 6.0 (5th Edition)“ (itl.tc/EssentialCSharp). Sie können ihn auf Facebook unter facebook.com/Mark.Michaelis, über seinen Blog unter IntelliTect.com/Mark, auf Twitter: @markmichaelis oder per E-Mail unter mark@IntelliTect.com erreichen.
Unser Dank gilt den folgenden technischen Experten von IntelliTect für die Durchsicht dieses Artikels: Kevin Bost, Andrew Scott und Michael Stokesbary