Von .NET 3.1 zu .NET 5 in acht Schritten

Im März migrierten wir die Seite der .NET User Group Bern von .NET 3.0 zu .NET 3.1. Der Aufwand war bei weitem nicht mehr so hoch als der Wechsel von .NET 2.2 zu .NET 3.0. Beim damaligen Wechsel waren die Integrationstests sehr hilfreich, denn diese lokalisierten die Breaking Changes des Entity Frameworks im Code. Im November erschien die Version .NET 5. Mit dieser Version ist der .NET Standard bereits wieder Geschichte. Für uns die Gelegenheit, den Aufwand einer Migration von .NET 3.1 zu .NET 5.0 an einem Beispiel durchzuführen.

1. Schritt: Global.json anpassen

Mit der Migration auf .NET 3.0 kam in unserer Solution die Global.json hinzu. Hier machten wir unsere erste Anpassung und setzten die Version auf .NET 5.

{
  "sdk": {
    	"allowPrerelease": false,
- "version": "3.1.402"    
+ "version": "5.0.100"
  }
}

2. Schritt: .NET Core App Version ersetzen

Unser Webprojekt ist eine MVC-Anwendung. In der csproj – Datei passten wir entsprechend das Target Framework von 3.1 auf 5.0 an.

<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
-   <TargetFramework>netcoreapp3.1</TargetFramework>
+   <TargetFramework>net5.0</TargetFramework>
...

3. Schritt: .NET Standard Bibliotheken ersetzen

Die Klassenbibliotheken unserer Anwendung waren bisher auf den .NET Standard ausgelegt. Bei diesen stellten wir in den csproj-Dateien ebenfalls das Target Framework auf .NET 5.0 um.

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
-   <TargetFramework>netstandard2.1</TargetFramework>
+   <TargetFramework>net5.0</TargetFramework>
  </PropertyGroup>
...

4. Schritt: XML-File Location anpassen

Bei den Dateien für die Dokumentationen, die wir primär zur API-Dokumentation mit Swashbuckle benötigen, mussten wir ebenfalls das Ausgabeverzeichnis anpassen. Neu ist der Ausgabeordner .net5.0.

<PropertyGroup>
- <DocumentationFile>bin\Debug\netstandard2.0\dnugbern.ViewModel.xml</DocumentationFile>
+ <DocumentationFile>bin\Debug\net5.0\dnugbern.ViewModel.xml</DocumentationFile>

5. Schritt: Aufräumen und neu erstellen

Wir nutzten die Gelegenheit den lokalen Zwischenspeicher der NuGet – Pakete aufzuräumen. Dies geht mit folgendem Befehl:

dotnet nuget locals --clear all

Die Anpassungen waren damit abgeschlossen und es ging daran, die NuGet-Pakete zu aktualisieren.

6. Schritt: Update Pakete

Für die Aktualisierung der Pakete nutzten wir die grafische Oberfläche zur Verwaltung der NuGet-Pakete. Da wir Remote mit Screensharing arbeiteten, konnten wir gemeinsam einen besseren Überblick über den Umfang bekommen. Im Solution-Explorer wählten wir dafür den Kontextmenü-Punkt «Manage NuGet Package for Solution»

Die Abbildung zeigt eine grafische Auflistung der NuGet Pakete, die auf .net 5 aktualisiert werden müssen

7. Schritt: Entity Framework

Nach der Aktualisierung der NuGet-Pakete kompilierten wir den Source-Code und erhielten einen Build-Error im Bereich von Entity Framework. Der Befehl Database.ExecuteSqlCommand war nicht mehr vorhanden, wurde von uns aber noch in einem Testprojekt verwendet. Diese Methode war bereits in Entity Framework Core 3 als veraltet markiert worden, was uns aber bisher nicht aufgefallen ist. Wir ersetzten diese Methode durch Database.ExecuteSqlRaw und der Source-Code kompilierte wieder fehlerfrei und alle Tests waren grün.

8. Schritt: Problem mit der Build-Pipeline

Als nächstes ging es darum die Anpassungen zu deployen. Unsere Pipeline gab folgendes Feedback:

“Azure Pipelines hosted agents have been updated and now contain .Net 5.x SDK/Runtime along with the older .Net Core version which are currently lts. Unless you have locked down a SDK version for your project(s), 5.x SDK might be picked up which might have breaking behavior as compared to previous versions. You can learn more about the breaking changes here: https://docs.microsoft.com/en-us/dotnet/core/tools/ and https://docs.microsoft.com/en-us/dotnet/core/compatibility/ . To learn about more such changes and troubleshoot, refer here: https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/build/dotnet-core-cli?view=azure-devops#troubleshooting

Wir ergänzten unsere Pipeline um folgenden Task, der die aktuelle Version künftig aus der global.json auslesen soll.

Die Abbildung zeigt die Darstellung des Use NuGet - Task mit den nötigen Einstellungen

In YAML ist die Definition wie folgt:

  - task: UseDotNet@2
    displayName: 'Use .NET Core sdk '
    inputs:
      useGlobalJson: true

Nochmal die Pipeline gestartet und wenige Minuten später das Resultat:

Die Abbildung zeigt einen Tweet mit den Hinweis, dass die Seite auf .NET 5 läuft

Ein Hinweis zum Schluss

Im 4. Schritt ist dir sicherlich aufgefallen, dass wir dnugbern im Namespace klein schreiben. Wir möchten darauf hinweisen, dass diese Entscheidung weder mit Bauhaus-Affinität noch Java-Vergangenheit zu tun hat. Die C# Styleguides sind uns sehr wohl bekannt. Unser Beweggrund bei dieser Entscheidung lag primär darin zu prüfen, ob lokale Regeln eines Systems, wie zum Beispiel Corporate Identity durch eine höhere Priorisierung die Kommunikation positiv verbessern können.

Erkenntnisse in diesem Bereich betrachten wir zu einem späteren Zeitpunkt.