.NET – Aus Alt mach Neu
Erfahrungsbericht über eine Migration von einer .NET Framework-Anwendung nach .NET
Erfolgreiche IT-Projekte stehen nach ca. 15 Jahren zwangsläufig vor den Herausforderungen einer Software-Modernisierung oder gar Ablöse durch eine Software-Migration. Selbst wenn der eigenentwickelte Softwareanteil stets gepflegt wurde, können Modernisierungsaufgaben aufgrund von nicht mehr gepflegten, nicht mehr aktuellen Abhängigkeiten und Laufzeiten entstehen. In der .NET-Welt bringt der Wechsel von .NET-Framework nach .NET eine solche Herausforderung mit sich, welche aber Dank der technologischen Nähe in Kombination mit einem geschickten Vorgehen gut zu meistern ist.
Seiteninhalt
Notwendigkeit einer Software-Migration
Im Jahr 2020 hat Microsoft mit .NET5 eine neue Plattform veröffentlicht, welche das .NET-Framework durch die Neuimplementierung aus dem moderneren .NET Core ersetzt. .NET Core galt allerdings selbst nicht als Migrationsempfehlung, da einige .NET-Framework-Funktionalitäten in .NET Core nicht zur Verfügung standen. Dies ist nun spätestens mit NET8 im Jahr 2024 überholt, sodass alle auf .NET-Framework basierende Alt-Anwendungen auf einen modernen Technologie-Stack gehoben werden sollten.
Durch die Einführung der .NET-Plattform initiierte Microsoft das Ende des vorherigen .NET-Frameworks. Viele Open Source-Bibliotheken stellen für das .NET-Framework mittlerweile auch keine neuen Versionen mehr zur Verfügung. .NET Framework-Anwendungen können somit nicht mehr von Weiterentwicklungen externer Bibliotheken profitieren. Weitaus kritischer ist es, dass auch gefundene Sicherheitslücken in den älteren Versionen nicht mehr geschlossen werden.
Die neue .NET-Plattform erhält jährlich ein neues Major-Update, welches stets Features sowie Performance-Optimierungen enthält. Die Version NET 8 ist beispielsweise in vielen Bereichen im Vergleich mit .NET 7 mehr als doppelt so schnell. Jede gerade Version (6, 8, 10…) von .NET erhält einen LTS-Support von drei Jahren, während die ungeraden Versionen mit der Veröffentlichung der nachfolgenden Version keinen Support mehr erhalten werden.
Eine Migration von .NET-Framework auf .NET ist demnach nicht nur sinnvoll, sondern notwendig, um eine sichere und technologisch moderne Anwendung betreiben zu können. Im Folgenden möchten wir unsere Praxiserfahrungen und Vorgehen bei einer solchen Migration vorstellen.
Definition Software-Migration: Grundlagen und Phasen
Unter der Software-Migration versteht man eine umfangreiche Änderung am vorhanden Quellcode dahingehend, dass eine verwendete Technologie oder Plattform/Programmiersprache
ausgetauscht wird. Diese Änderungen können je nach Austausch unterschiedlich umfangreich ausfallen. Bei dem Austausch der Plattform/Programmiersprache kann es zum Beispiel durchaus sinnvoll sein, die gesamte Software-Architektur einer Anwendung abzuändern.
Eine Software-Migration erfolgt typischerweise in zwei Phasen: Zuerst sollte die vorhandene Anwendung analysiert und die erforderlichen Anpassungen erfasst werden. Auf dieser Basis kann eine Migrationsstrategie erarbeitet werden. Einzelne Komponenten können identifiziert und jeweils passende Zielkomponenten aus der neuen Plattform bestimmt werden. Darauf folgt eine Planung der Reihenfolgen der anstehenden Änderungen. Im eigentlichen Durchführungsschritt (Phase 2) wird der vorhandene Quellcode angepasst, sodass die neue Technologie oder Plattform eingesetzt werden kann. Abschließend muss die korrekte Verhaltensweise der migrierten Anwendung validiert und getestet werden.
Grundlegend existieren eine sogenannte „weiche“ und eine „harte“ Migrationsstrategie. Bei einer „weichen Migration“ erfolgen die Änderungen schrittweise, wobei Teilfunktionalitäten der Anwendung angepasst werden, während sie weiterhin in Betrieb ist. Bei dieser Strategie werden die Auswirkungen auf die Anwendung und somit das Risiko von ungewollten Änderungen minimiert. Die zum Teil migrierte Anwendung kann schneller getestet und mit (möglicherweise vorhandenen) neueren Features veröffentlich werden. Dem gegenüber kann in Summe ein höherer Testaufwand für die gesamte Migration entstehen, da bereits migrierte und getestete Komponenten durch mögliche Seiteneffekte erneut getestet werden müssen.
Von einer „harten Migration“ spricht man, wenn die migrierte Anwendung erst in Betrieb genommen wird, wenn der gesamte Quellcode vollständig angepasst und getestet wurde („Big Bang“). Bei einer solche Migration gibt es meist für die durchzuführenden Änderungen einen eigenen und langlebigen Entwicklungsstrang, da die Anwendung währen der Migration weiterentwickelt werden muss. Hier fallen bedingt durch die Weiterentwicklung höhere Synchronisationsaufwände an.
Erfahrungsbericht: Erfolgreiches Vorgehen einer .NET-Migration
Die zu migrierende Anwendung war unsere Low Code-Lösung CoreFrame. Hierbei handelt es sich um eine pluginbasierte und mandantenfähige Client/Server-Anwendung, welche auf der .NET-Framework-Plattform betrieben wird. Sie wurde über mehrere Jahre entwickelt und ist bei über 500 Kunden installiert, wobei manche Kundensysteme über 70 Mandanten verfügen.
Das Fachkonzept bestand aus mehreren Projekten (Klassenbibliotheken). Das Server-Projekt nutzte die ASP.NET MVC-Bibliothek zur Verarbeitung von Anfragen des dazugehörigen HTML-Clients. Zu der Projektmappe der Anwendung gehörten zusätzlich Unit-Test-Projekte und weitere Tools, die zum Betrieb der Anwendung beitragen. Insgesamt bezifferte sich die Größe der Anwendung auf mehr als 50 Projekte in der Projektmappe. Die Anwendung wurde in einem CI Build-Server integriert, auf einem Jenkins gebaut, getestet und veröffentlicht.
Strategie zur .NET-Migration: Wie wir die Modernisierung geplant haben
Es wurde der Ansatz der weichen Migration gewählt, da die Anwendung fortlaufend weiterentwickelt wurde und beide .NET-Plattformen in einer Projektmappe ausführbar sein sollten. Die Migrationsfortschritte und neue Funktionalitäten sollten so schnell wie möglich zusammengeführt werden. Dieser Ansatz erlaubte es, dass der aktuelle Stand der Anwendung auf beiden Plattformen ausführbar und testbar war.
Zu Beginn wurde die Anwendung analysiert und die Projekte der Projektmappe in einzelne Phasen eingeteilt. Das Ziel aller Phasen war es, dass die Anwendung nach dem Abschluss einer solchen Phase vollständig auf der bisherigen .NET-Framework-Plattform lauffähig war und korrekt arbeitete. Zuerst sollte das Fachkonzept migriert werden. Anschließend sollten Teile des Server-Projektes, die auf beiden Plattformen genutzt werden könnten, in ein eigenes Projekt ausgelagert und migriert werden, so dass so wenig plattformspezifischer Code wie möglich entstehen würde. In der darauffolgenden Phase wurde in Anlehnung an den vorhandenen Code eine ASP.NET Core Server Implementierung entwickelt, welche parallel zum vorhandenen ASP.NET MVC Projekt existieren sollte. In der abschließenden Phase wurden die Tools und die CI Pipeline migriert.
Folgende Phasen wurden definiert:
Phasen einer Software-Migration: Wie wir die Migration durchgeführt haben
Technisch ist eine weiche Migration durch den Einsatz von .NET-Standard möglich. Eine .NET-Standard Bibliothek kann sowohl in .NET-Framework als auch in .NET nutzt werden. .NET-Standard kann als ein universellen Schnittstellenvertrag für .NET-Plattformen angesehen werden. Er definiert eine gemeinsame kleinste SDK-Version und Laufzeit, welche über alle Plattformen hinweg gilt.
Phase 1: Migration des Fachkonzepts
Die Migration der Fachkonzept-Projekte kann grob in drei Schritte zusammenfassen werden:
- Umstellung der Projektdatei
- Erneuerung oder Austausch der verwendeten Bibliotheken
- Anpassungen am eigenen Quellcode vornehmen
Microsoft hat ebenfalls das Tool „.NET Upgrade Assistant“ bereitgestellt. Dieses Tool unterstützt die Entwicklerinnen und Entwickler bei der Migration eines Projektes. Es wurde zuerst als Konsolenanwendung verwendet, mittlerweile wurde es vollständig in Visual Studio mit einer grafischen Oberfläche integriert.
Mit Hilfe des „.NET Upgrade Assistant“ transformierten wir die Projektdateien (Dateiendung .csproj) in das neue SDK-Format mit .NET-Standard 2.0 als Zielplattform. Die Projektdatei benötigte im Anschluss noch manuelle Nacharbeiten, da manche Build-Events (zum Beispiel das Kopieren von Dateien) nicht automatisch in das neue Format migriert werden konnten.
Anschließend wurden die im Projekt verwendeten Bibliotheken angepasst. Wenn eine Bibliothek in der verwendeten Version bereits in .NET-Standard 2.0 vorlag, mussten keine Änderungen daran vorgenommen werden. Andernfalls prüften wir, ob eine neuere Version der gleichen Bibliothek diese Zielplattform unterstützte. In diesem Fall führten wir ein Update der Bibliothek durch. Wenn auch ein Update der Version keine Option darstellte, musste die Bibliothek gegen eine andere, gleichwertige, Bibliothek ausgetauscht werden. Im Bezug zur Plattformunabhängigkeit, die wir erreichen wollten, gab es noch einen interessanten Sonderfall: Die Bibliothek „System.Drawing“ ist zwar .NET-Standard 2.0 kompatibel, kann aber nicht unter Linux verwendet werden, da sie ausschließlich auf Windows-interne Drawing-Funktionen verweist. Um dieses Problem zu lösen und gleichzeitig eine Plattformunabhängigkeit zu erreichen, bietet es sich an, z. B. auf die Open Source-Bibliothek „SkiaSharp“ zu wechseln.
Zuletzt wurde der Quellcode des Projektes an die neue Zielplattform und die neuen Bibliotheken angepasst. Dies war je nach notwendigem Bibliotheksaustausch unterschiedlich aufwändig.
Nachdem alle Fachkonzept-Projekte migriert wurden, wurde die Korrektheit mit Hilfe der Unit-Test-Projekte validiert. Die Tests wurden zuerst auf der .NET-Framework-Plattform ausgeführt. Im nächsten Schritt wurden die gleichen Tests auf der neuen .NET-Plattform ausgeführt (hierzu mussten die Testprojekte minimal angepasst werden).
Hier traten meist Laufzeitfehler in der Anwendung auf, da die Projekte unter .NET-Standard 2.0 zwar fehlerfrei kompilierten, aber teilweise interne Funktionalitäten unter .NET fehlten (ähnlich zu der Problematik mit „System.Drawing“). Hier war es erforderlich, entweder andere „.NET-Klassen“ zu nutzen oder gar eine ganz neue Bibliothek einzusetzen. In manchen Fällen wurden zwei unterschiedliche Implementierungen entwickelt, welche als abstrahierte Abhängigkeit je nach Plattform genutzt wurde.
Nachdem auch unter .NET alle Tests erfolgreich durchliefen, wurde die Phase erfolgreich beendet.
Phase 2: Migration von Teilfunktionalitäten aus dem Serverprojekt (ASP.NET MVC)
In dieser Phase wurde das vorhandene Server-Projekt überarbeitet. Es wurden die Logiken aus den ASP.NET MVC spezifischen Klassen (Controller, Filter und Views) extrahiert und in ein neues .NET-Standard 2.0 Projekt verschoben. Spezifischer Plattform-Code wurde, wenn nötig, abstrahiert und als Abhängigkeit verfügbar gemacht. Diese verschobenen Logiken wurden von den ASP.NET MVC spezifischen Klassen anschließend nur noch aufgerufen. Die bisherige ASP.NET MVC Template-Engine wurde durch eine .NET-Standard-Bibliothek ausgetauscht, so dass die Server generierten Views auch ausgelagert werden konnten.
Durch diese Umstellung wurde erreicht, dass der notwendige Anteil an plattformspezifischen Code für .NET-Framework und .NET (in Zukunft) deutlich reduziert werden kann. Eine Anpassung an der ausgelagerten Logik im späteren Parallelbetrieb müsste somit nur einmal durchgeführt werden und kann direkt auf beiden Plattformen verwendet werden.
Phase 3: Migration von ASP.NET MVC nach ASP.NET Core
Zu Beginn wurde ein neues ASP.NET Core-Projekt in der Projektmappe für .NET erstellt. Alle erforderlichen ASP.NET MVC-spezifischen Funktionen wurden unter Verwendung der ASP.NET Core-Infrastruktur implementiert. Dabei konnten wir auf die in Phase 2 ausgelagerte Logik zurückgreifen, so dass der Aufwand in dieser Phase hauptsächlich durch die Anpassung an die neue Infrastruktur und ihr teilweise unterschiedliches Verhalten zustande gekommen ist. ASP.NET Core ist im Vergleich zu ASP.NET MVC sehr performant und sehr gut skalierbar. Diese Verbesserungen wurden mit Änderungen der Architektur erreicht.
Beispielsweise kann man das Session-Verhalten erwähnen, welches sich drastisch geändert hatte. Durch die Auslegung auf horizontale Skalierung, war es erforderlich, dass die Sessions mit all ihren gespeicherten Variablen serialisiert werden konnten. Denn die Serialisierung erlaubt es, dass eine Session auf einem anderen ASP.NET Core Server im gleichen Verbund genutzt werden kann. Eine weitere Verhaltensänderung bestand beim „Session-Locking“. ASP.NET MVC erlaubt nur eine begrenzte Menge von gleichzeitigen Anfragen in einer Session. Eine Anfrage, die diese Menge überschreiten würde, wird so lange blockiert, bis die Bearbeitung einer früher eingegangenen Anfrage abgeschlossen ist. Diese Einschränkung ist bei ASP.NET Core nicht mehr vorhanden, wodurch sich eine Steigerung der Performance begründen lässt. Die Anwendung wurde an diese neuen Verhaltensweisen erfolgreich angepasst.
Weitere notwendige Anpassungen entstanden durch unterschiedliche Namespaces (vor allem bei Klassen wie dem HttpContext oder in ActionFilter-Implementierungen) sowie durch den Wegfall der OWIN-Pipeline. ASP.NET Core führte das Konzept der Middleware-Pipeline ein, welches als Weiterentwicklung der OWIN-Architektur gesehen werden kann. Diese Pipeline besteht aus hintereinander verketteten Middleware-Klassen, welche die eingehenden Anfragen bearbeiten. Jede Middleware führt eine bestimmte Aufgabe, wie beispielsweise Authentifizierung, Logging oder Komprimierung, in der Bearbeitung einer Anfrage aus.
Phase 4: Migration der Tools sowie Anpassung der CI Pipeline
Die abschließende Phase verlief ebenfalls reibungslos und profitierte von unserer gesammelten Erfahrung. Dank der CLI (Command Line Interface) von Microsoft für .NET war es uns möglich, die CI-Pipeline mit minimalem Aufwand anzupassen.
“Ich habe bereits einige Big-Bang-Migrationen begleiten dürfen. Leider sind diese häufig nur technisch begründet und echte Mehrwerte für die Geschäftsebene bleiben unberücksichtigt. Weiche Migrationen – wie im beschriebenen Anwendungsfall – erlauben neben der Beseitigung von technischen Schulden weiterhin die z.B. sprintbasierte Lieferung von neuen Features.
Wann immer sinnvoll, würde ich versuchen, eine solche Migrationsstrategie zu bevorzugen. Gerade die .NET-Framework nach .NET-Migration erlaubt dies häufig.”
Thomas Alken
Senior Software Developer
Fazit
Alle Ziele der Migration wurden erreicht, wodurch der Ansatz einer sanften Migration als voller Erfolg betrachtet werden kann. Weder die parallele Weiterentwicklung noch der laufende Betrieb wurden durch die Migration beeinträchtigt. Die Anwendung ist nun in der Lage, bei Kunden auf beiden Plattformen reibungslos betrieben zu werden.
Mittlerweile wird die Anwendung containerisiert in Azure betrieben. Mit der erfolgreichen Migration stehen nun alle Türen offen für die Integration neuer Technologien und die Weiterentwicklung der Anwendung.
Generell bietet die Migration von .NET-Framework auf .NET viele Vorteile:
- Modern und zukunftssicher: Migrierte Anwendungen können die neuesten Bibliotheken und Sprachfeatures einsetzen. Sicherheitslücken werden aktiv gesucht und können schnell geschlossen werden.
- Langfristige Unterstützung: Während .NET-Framework nicht mehr aktiv weiterentwickelt wird, wird .NET in einem jährlichen Zyklus verbessert und weiterentwickelt.
- Plattformunabhängigkeit: Durch .NET können plattformunabhängige Anwendungen erstellt werden, die auf verschiedenen Betriebssystemen wie Windows, Linux und macOS ausgeführt werden können. Eine migrierte Anwendung kann somit günstigeren Linux Maschinen betrieben werden.
- Performance: .NET ist grundlegend schneller und ressourcenschonende. Die Migration kann dazu beitragen, die Geschwindigkeit der Anwendungen zu steigern und den Ressourcenverbrauch zu verringern.
- Einsatz moderner Technologien: .NET bietet native Unterstützung für moderne Technologien wie Microservices, Containerisierung und Cloud-native Entwicklung. Migrierte Anwendungen können beispielsweise mit wenig Aufwand in Azure oder Docker betrieben werden.
- Open Source: .NET ist eine vollständige Open-Source-Plattform und verfügt über eine aktive Entwicklergemeinschaft sowie eine Vielzahl an zugänglichen Open-Source-Bibliotheken.
SMF für eine erfolgreiche IT-Modernisierung
Wir entwickeln schon seit mehr als 35 Jahren kundenspezifische Software und stellen intelligente Softwarelösungen zur Optimierung von Geschäftsprozessen bereit. „Altlasten“ beherrschen wir und kennen die Herausforderungen und Fallstricke, die bei derartigen Projekten auftreten können.
Für die Modernisierung von Altsystemen beraten wir Unternehmen bei der Auswahl geeigneter Softwaretechnologien, der Erfassung von Anforderungen sowie der Erarbeitung von System- und Anwendungsarchitekturen. Lassen Sie sich von unserem Expertenteam beraten und fordern Sie jetzt eine erste kostenfreie Analyse an. Gemeinsam starten wir mit vertrauten Anwendungen in ein neues Software-Zeitalter!
Bei weiteren Fragen rund um eine Migration von einer .NET Framework-Anwendung nach .NET kontaktieren Sie uns gern.
Pflicht für alle Anfragen zu unseren Angeboten. *
Weiterführende Links