Agile schützt vor Torheit nicht Das Passwort, bitte

Migration zu ASP.NET Core RC2

Published on Friday, May 27, 2016 6:53:35 AM UTC in Programming

Der Umfang der Dokumentation zur Migration von ASP.NET Core RC1 (ehemals: ASP.NET 5 RC1) zu ASP.NET Core RC2 lässt schon vermuten, dass das Upgrade nicht unbedingt ein trivialer Schritt ist. Gute Einstiegspunkte finden sich bei "Migrating from DNX to .NET Core CLI" und "Migrating from ASP.NET 5 RC1 to ASP.NET Core". Um nicht wieder und wieder in dieselben Fallen zu tappen, habe ich mir diese Checkliste erstellt, wenn es um das Umstellen von Projekten geht.

0. Vorbereitung und Installation

Zunächst einmal gilt es, die Überreste des alten ASP.NET 5 RC1 vom System zu entfernen, was theoretisch wie gewohnt über die Systemsteuerung funktioniert. Leider war der ursprüngliche Installer eine EXE-Datei statt eines MSI, so dass Windows diesen nicht automatisch weggesichert hat. Wer den Installer zwischenzeitlich bewusst oder unterbewusst (Browser Cache!) gelöscht hat, kann die Deinstallation nicht durchführen. Man muss zunächst den alten Installer wieder herunterladen und der Deinstallationsroutine mitteilen, wo er liegt (GitHub Issue hierzu). Download-Links zum Installer:

Nach der Deinstallation kann man dann RC2 installieren. Am einfachsten geht das über den Installer des Tooling Preview 1 für Visual Studio 2015, der auch gleich das .NET Core SDK mitinstalliert.

Was man eher selten als Hinweis findet ist, dass man auch eine Vorab-Version des NuGet Package Managers installieren soll, zum aktuellen Zeitpunkt ist das die Version 3.5 Beta.

Generell empfehle ich, vor der Installation auf http://dot.net vorbeizusehen und die dort aktuellen Links abzugreifen, da sie sich ggfs. zwischenzeitlich geändert haben könnten.

1. project.json

Das Aufräumen kann beginnen :). Ein grundsätzlich guter Ansatz ist, zunächst ein neues, leeres RC2-Projekt zu erstellen, damit man eine Vergleichsmöglichkeit hat und einfacher z.B. Versionsnummern von Dependencies u.ä. übernehmen zu können, statt diese mühsam heraussuchen und manuell eintippen zu müssen.

  • Ersetze compilationOptions mit buildOptions. Wichtig ist die Option "emitEntryPoint": true darin, sowie bei der Verwendung von On-the-Fly zu kompilierenden Dateien wie bei MVC (Razor Views) die Options "preserveCompilationContext": true
  • Entferne den command-Knoten vollständig. Das Konzept gibt es in dieser Form nicht mehr.
  • Entferne exclude-Einträge bzw. verschiebe sie hin zu buildOptions/compile/exclude
  • Entferne publishExclude-Einträge bzw. verschiebe sie hin zu publishOptions/exclude
  • Ersetze alle rc1-final-Einträge in dependencies mit dem Pendant rc2-final. Da es auch Umbenennungen gab und teilweise Pakete nicht mehr referenziert werden müssen (Tag Helpers), tut man sich am einfachsten, wenn man die dependencies aus einem neuen, leeren Projekt übernimmt.
  • Ersetze alle Framework-Monikers mit den neuen/richtigen. Also etwa dnx461/dnx451 mit net461/net451 etc.
  • Füge einen neuen tools-Eintrag hinzu; diesen übernimmt man ebenfalls am besten aus einem neuen, leeren Projekt.
  • Füge runtimeOptions hinzu. Insbesondere wichtig für ASP.NET Core-Anwendungen ist der Eintrag "gcServer": true; der zweite Eintrag sollte "gcConcurrent": true sein.

Das war es auch schon mit der grundlegenden Projektkonfiguration.

2. launchsettings.json

Hier befinden sich die Einträge, die Visual Studio zum Starten (bzw. Debuggen) der Anwendung bereitstellt. Die Datei ist etwas versteckt im Unterordner "Properties" zu finden. Da das Konzept der Kommandos in der project.json in der bisherigen Form abgeschafft wurde, muss der dort vorhandenen Eintrag web entweder entfernt oder durch das eingebaute Kommando project ersetzt werden. Etwa so:

"BeliebigerName": {
  "commandName": "Project",
  "launchBrowser": true,
  "launchUrl": "http://localhost:5000",
  "environmentVariables": {
    "ASPNETCORE_ENVIRONMENT": "Development"
  }
}

3. Startup.cs

Da am Konzept des Bootstrappings am meisten verändert wurde, sind viele Teile der Startup.cs betroffen. Insbesondere:

  • Entferne die statische Main-Methode.
  • Entferne Aufrufe zur IISPlatformIntegration aus der Configure-Methode.
  • Ersetze alle AspNet-Usings mit AspNetCore.
  • Ersetze IApplicationEnvironment.ApplicationBasePath mit IHostingEnvironment.ContentRootPath.
  • Ersetze die Fluid-Variante ReloadOnChanged() der Konfiguration mit dem Argument reloadOnChange in der Methode AddJsonFile.
  • Ersetze .AddInstance()-Aufrufe auf der ServiceCollection mit .AddSingleton().
  • Füge .SetBasePath(hostingEnvironment.ContentRootPath) zur ConfigurationBuilder-Aufrufkette hinzu.

Der eigentliche Einstiegspunkt der Anwendung sollte der Übersichtlichkeit halber in eine separate Program.cs wandern:

4. Program.cs (neu)

Bei ASP.NET Core RC2-Anwendungen handelt es sich um gewöhnliche Konsolenprogramme, deren Main-Methode das eigentliche Bootstrapping vornimmt. Ein vollständiges Beispiel dieser Methode sieht etwa so aus:

public static void Main(string[] args)
{
    var host = new WebHostBuilder()
        .UseKestrel()
        .UseContentRoot(Directory.GetCurrentDirectory())
        .UseIISIntegration()
        .UseStartup<Startup>()
        .Build();

    host.Run();
}

5. appsettings.json

Die Benennung und Reihenfolge der Log-Levels hat sich verändert. Der frühere Eintrag Verbose wurde umbenannt in Trace und ist jetzt in der Ausführlichkeit unterhalb von Debug angesiedelt. Ggfs. sind also Einträge hier zu korrigieren oder abzuändern.

6. Projekt-Eigenschaften

Aus Kompatibilitätsgründen mit anderen Plattformen wurde die Benennung der Umgebungsvariablen angepasst. Statt des : wird nun ein Underscore _ zur Trennung verwendet. Gleichzeitig wurde die Bennenung vereinheitlicht; Variablen beginnen nun mit ASPNETCORE.

Daraus ergibt sich unmittelbar, dass man in den Projekt-Eigenschaften den bisherigen Eintrag Hosting:Environment umbennen sollte in ASPNETCORE_ENVIRONMENT.

7. web.config

Die Datei web.config wandert vom Unterordner wwwroot (bzw. dem für das Projekt abweichend konfigurierten Root-Ordner) ins Stammverzeichnis. Der Inhalt muss sich auf Grund der geänderten Integration mit IIS ändern zu:

<?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>

8. Suchen und Ersetzen

Nachdem man nun die chirurgischen Eingriffe hinter sich hat, kann man mit der großen "Suchen und Ersetzen"-Keule weitermachen.

  • Ersetze global alle using Microsoft.AspNet.-Strings mit using Microsoft.AspNetCore.
  • Ersetze global auch alle Namespace-Verweise in (Razor-)Views (Microsoft.AspNet.) mit dem neuen Namespace (Microsoft.AspNetCore.)
  • Ersetze global alle synchronen Aufrufe von ViewComponents mit dem asynchronen Gegenstück (siehe https://docs.asp.net/en/latest/migration/rc1-to-rc2.html#viewcomponents-changes)
  • Ersetze global in allen Validation Summary-Elementen ValidationSummary.All mit dem Wert All

9. Class Libraries überarbeiten

Die bisherigen "Package"-Class-Libraries funktionieren weiterhin. Allerdings muss man auch hier die unter 1. beschriebenen Änderungen an der project.json durchführen, insbesondere die Anpassung der Framework Monikers, falls nötig, und natürlich die Aktualisierung der Dependencies.

10. Tooling

Momentan hat insbesondere ReSharper größere Probleme mit ASP.NET Core RC2 (Beispiel-Issue bei JetBrains). Am nervigsten ist, dass die Razor-Views teilweise komplett kaputt sind und Dutzende "False Positives" verursachen bzw. ReSharper mit ständigen Vorschlägen stört, welche Referenzen man doch bitte hinzufügen sollte. Zur Lösung gibt es zwei Möglichkeiten. Entweder man schaltet die Razor-Unterstützung von ReSharper ab:

ReSharper-TurnOff-Razor.png

Oder aber man wagt sich als Bleeding Edge-Adopter daran, die gestern (26.05.) veröffentlichte EAP 1 von ReSharper 2016.2 zu installieren. Meiner Erfahrung nach repariert sie diese Fehler tatsächlich recht zuverlässig.

Ansonsten empfehle ich noch, nach der Migration kurz Visual Studio zu schließen, die .vs-Ordner des Projekts zu löschen, und dann die Solution neu zu öffnen - ich hatte bei zwei Versuchen ansonsten teils komische Effekte, die nach einem Neustart von Visual Studio aber verschwunden waren.

Danach bleibt nur noch, alle verbleibenden Compile-Fehler zu beheben, sollten noch welche übrig sein ;).

Known Issues

Das ValidationSummary-Control konnte ich bisher nicht zuverlässig in Kombination mit asynchronen ViewComponents zum Laufen bekommen. Ich erhalte reproduzierbare NullReferenceExceptions, die mich stark an ein früheres Problem mit derselben Komponente erinnern.

Viel Erfolg!

Tags: ASP.NET Core