Upgrade to Pro — share decks privately, control downloads, hide ads and more …

.NET 4 Migration

Pawel Gerr
February 26, 2024

.NET 4 Migration

Pawel Gerr

February 26, 2024
Tweet

More Decks by Pawel Gerr

Other Decks in Programming

Transcript

  1. .NET 4, OWIN, WCF: Time to say goodbye Migration zu

    modernem serverseitigem .NET Pawel Gerr @pawelgerr Consultant
  2. • Motivation: • Was spricht gegen .NET 4 • Was

    spricht für .NET 8 • Vorteile für Entwickler, das Projekt, das Unternehmen, die Endanwender • Was sind die Migrationsängste • Migrationsvorbereitung • Gute Vorbereitung ist die halbe Miete • Was lässt sich nicht vorbereiten? • Migrationsansätze • Migration von OWIN Controllers und WCF Services .NET 4, OWIN, WCF: Time to say goodbye Agenda Migration zu modernem serverseitigem .NET
  3. Migration von Clients • WinForms und WPF werden heute nicht

    behandelt • Einige Alternativen: • Angular (https://www.thinktecture.com/technologien/angular/) • Blazor WebAssembly (https://www.thinktecture.com/technologien/blazor/) .NET 4, OWIN, WCF: Time to say goodbye Migration zu modernem serverseitigem .NET Um was geht es heute nicht
  4. .NET 4, OWIN, WCF: Time to say goodbye Migration zu

    modernem serverseitigem .NET Migrationsmotivation Vorteile und Effekte des Wechsels auf modernes .NET 8
  5. Was spricht gegen .NET 4 • Sinkender Support der Bibliotheken

    • ASP.NET Core bis Version 2.1 • Entity Framework Core bis Version 3.1 • AutoMapper bis Version 10 • Etc. • Kein vollständiger Zugang zu neue Features in C# und .NET Runtime, bspw. • Annotation von Nullable-Reference-Types fehlt in vielen APIs • Keine neuen GC- und Jit-Features, wie DATAS und Dynamic PGO • Läuft nur unter Windows (und Mono bringt andere „Herausforderungen“ mit sich) • Kein Betrieb in Containerumgebungen • Assembly-Redirects ☺ .NET 4, OWIN, WCF: Time to say goodbye Motivation Migration zu modernem serverseitigem .NET
  6. Was spricht für .NET 8 • Basiert auf .NET-Rewrite •

    Optimierte Datenstrukturen • Geringerer Ressourcenverbrauch • Bessere Performance • Minimal API und gRPC (Goodbye OWIN und WCF) • Aktive Weiterentwicklung Quelle: .NET Conf 2023 - .NET 7 vs .NET 8 (https://www.youtube.com/watch?v=YiOkz1x2qaE) .NET 4, OWIN, WCF: Time to say goodbye Motivation Migration zu modernem serverseitigem .NET
  7. .NET 4, OWIN, WCF: Time to say goodbye Migration zu

    modernem serverseitigem .NET Demo Optimierte Datenstrukturen .NET 8
  8. Optimierte Datenstrukturen .NET 4, OWIN, WCF: Time to say goodbye

    Migration zu modernem serverseitigem .NET Motivation 80 B 20 B 80 B 20B Ansatz .NET 8 Ansatz .NET 4 80 B 20B Pointer + Länge 70 B SubString() Trim() SubString() Slice() Pointer + Länge Trim() Pointer + Länge Slice()
  9. Vorteile durch Umstieg auf .NET 8 .NET 4, OWIN, WCF:

    Time to say goodbye Migration zu modernem serverseitigem .NET Motivation Technische Sicht Business-Sicht Entwicklervorteile • Modernen Frameworks, APIs und Datenstrukturen • Größere Auswahl an (Open-Source) Bibliotheken • Bessere Dokumentation und Tutorials Projektvorteile • Schnellere Entwicklung (durch Bibliotheken anstatt Eigenimplementierung) • Neue Deployment-Möglichkeiten, wie Kubernetes Unternehmensvorteile • Weniger Lizenzkosten durch Umstieg auf Linux • Bessere Chance bei den Bewerbern auf dem Arbeitsmarkt Endanwendervorteile • Reaktionsschnellere Anwendung • Feedback eines Kunden: Die Anwendung fühlt sich flüssiger an
  10. Was sind die Migrationsängste • Anfänglichen Ungewissheit • Nutzen wir

    inkompatible Bibliotheken? • Welche APIs stehe nicht mehr zur Verfügung? • Wie groß ist der zeitliche Aufwand? • Weiterentwicklung der Anwendung kann während der Migration nicht eingestellt werden .NET 4, OWIN, WCF: Time to say goodbye Motivation Migration zu modernem serverseitigem .NET
  11. .NET 4, OWIN, WCF: Time to say goodbye Migration zu

    modernem serverseitigem .NET Migrationsvorbereitung Migration optimal vorbereiten
  12. Mögliche Modernisierungen des Codes vor Migration • Grund: Reduzierung von

    Merge-Konflikten während der Migration • Abbau anstehender technischer Schulden vorziehen (wenn’s sinnvoll!) • Backend-Code vom Frontend-Code (wie WPF) in unterschiedliche Projekte aufteilen • Projektweite Anpassungen an Code-Styles vorziehen (wie namespace/using declarations, Einrückungen, etc.) • Bekannte veraltete APIs und Bibliotheken auf zukunftsichere Alternativen austauschen • Mit keinen oder akzeptablen Änderungen am Verhalten .NET 4, OWIN, WCF: Time to say goodbye Gute Vorbereitung ist die halbe Miete namespace MyApp { public class MyClass { } } namespace MyApp; public class MyClass { } Migration zu modernem serverseitigem .NET
  13. Umstellung auf SDK-basierte Projekte .NET 4, OWIN, WCF: Time to

    say goodbye Gute Vorbereitung ist die halbe Miete <?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="4.0" DefaultTargets="Build" ...> <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props"/> <PropertyGroup> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> <OutputType>Exe</OutputType> <TargetFrameworkVersion>v4.8.1</TargetFrameworkVersion> </PropertyGroup> <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net4.8</TargetFramework> </PropertyGroup> Migration zu modernem serverseitigem .NET
  14. Erhöhung der Version von C# • Bestimmte Sprachfeatures stehen auch

    in .NET 4 zur Verfügung (Setzt das aktuelle .NET 8 SDK voraus) .NET 4, OWIN, WCF: Time to say goodbye Gute Vorbereitung ist die halbe Miete <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net4.8</TargetFramework> <LangVersion>12</LangVersion> </PropertyGroup> Migration zu modernem serverseitigem .NET
  15. BinaryFormatter • BinaryFormatter oder vergleichbare Alternative nicht verfügbar • Migration

    hängt von der Verwendungsart ab • Serialisierung von Nachrichten • JSON (System.Text.Json, Newtonsoft.Json) • Protobuf • MessagePack • Klonen von Objekten • Manuell, via Reflection oder Roslyn Source Generator • Ggf. mithilfe von MemberwiseClone, um zumindest immutable Werte (int, string, etc.) nicht händisch klonen zu müssen • Weitere Infos: https://github.com/dotnet/announcements/issues/293 .NET 4, OWIN, WCF: Time to say goodbye Gute Vorbereitung ist die halbe Miete Migration zu modernem serverseitigem .NET
  16. Konfiguration (IConfiguration) • ConfigurationManager und ConfigurationSection/ConfigurationElement werden unterstützt • Benötigt

    NuGet-Paket System.Configuration.ConfigurationManager • Aber, App.config/Web.config sind überholt und sollten nicht mehr verwendet werden • Umstellung auf IConfiguration nicht erforderlich, aber empfehlenswert • Eröffnet neue Möglichkeiten der Konfiguration (JSON-Dateien, Konsolenargument, Umgebungsvariablen, etc.) • Viele Bibliotheken unterstützen von Haus aus IConfiguration .NET 4, OWIN, WCF: Time to say goodbye Migration zu modernem serverseitigem .NET Gute Vorbereitung ist die halbe Miete
  17. Dependency Injection (DI) • Legacy-Anwendungen mit OWIN (und WCF!) unterstützen

    Dependency Injection • Erfahrungsgemäß wird Autofac eingesetzt • Nicht selten mit Memory Leaks • Umstellung auf Microsoft Dependency Injection (MS DI) nicht erforderlich, aber empfehlenswert • Bietet Möglichkeit die Abhängigkeiten zu validieren, um ggf. Memory Leaks aufzudecken • Viele Bibliothek unterstützen MS DI von Haus aus • Bessere Performance bzw. geringerer Overhead als bspw. Autofac • Weniger Stolperfallen bei der Verwendung .NET 4, OWIN, WCF: Time to say goodbye Migration zu modernem serverseitigem .NET Gute Vorbereitung ist die halbe Miete
  18. Dependency Injection - Stolperfallen Case 3: Was passiert wenn man

    im Case 2 die Reihenfolge umdreht? .NET 4, OWIN, WCF: Time to say goodbye Migration zu modernem serverseitigem .NET Gute Vorbereitung ist die halbe Miete // Setup public record Parent(Child Child); public class Child { public int Value { get; set; } } var containerBuilder = new ContainerBuilder(); containerBuilder.RegisterType<Parent>().SingleInstance(); containerBuilder.RegisterType<Child>().SingleInstance(); using var container = containerBuilder.Build(); using var scope = container.BeginLifetimeScope(); // Case 1 var parent = scope.Resolve<Parent>(); Console.WriteLine(parent.Child.Value); // 0 // Case 2 var factory = scope.Resolve<Func<Child, Parent>>(); var nonSingletonChild = new Child { Value = 1 }; var nonSingletonParent = factory(nonSingletonChild); Console.WriteLine(nonSingletonParent.Child.Value); // 1 var parent = scope.Resolve<Parent>(); Console.WriteLine(parent.Child.Value); // ? Tipp: Es ist nicht 0
  19. OWIN (Controller) – HttpResponseMessage • Controller mit HttpResponseMessage auf IHttpActionResult

    umstellen • Methoden wie Ok() oder NotFound() für die Rückgabe von Werten verwenden • Gründe: • IHttpActionResult lässt sich mit "Suchen und Ersetzen" zu IActionResult ändern • Mehrere Methoden, wie Ok(), gibt es auch in ASP.NET Core .NET 4, OWIN, WCF: Time to say goodbye Migration zu modernem serverseitigem .NET Gute Vorbereitung ist die halbe Miete public class MyController : ApiController { public IHttpActionResult Get() { if (…) { return NotFound(); } return Ok(); } }
  20. OWIN (Controller) – Technische Schulden • HttpContext.Current außerhalb der Controller

    entfernen/ersetzen bspw. • Abstrahieren und als Methodenargument übergeben oder • Via Ambient Context Pattern: analog zu IHttpContextAccessor • Analog zu oben: HttpRequest, HttpResponse und HttpResponseException entfernen/ersetzen • Empfang oder Rückgabe von JToken/JObject sollte vermieden werden • Beachte: ASP.NET Core verwendet standardmäßig System.Text.Json anstatt Newtonsonft.Json .NET 4, OWIN, WCF: Time to say goodbye Migration zu modernem serverseitigem .NET Gute Vorbereitung ist die halbe Miete
  21. WCF – WebGet/WebInvoke • WCF Services mit WebGetAttribute und WebInvokeAttribute

    zu Controllers konvertieren • Grund: Erfahrungsgemäß verhalten sich diese Services wie Controllers, somit hat man 2 Implementierung für das gleiche Konzept • Analog zu HttpContext: OperationContext.Current entfernen/ersetzen .NET 4, OWIN, WCF: Time to say goodbye Migration zu modernem serverseitigem .NET Gute Vorbereitung ist die halbe Miete
  22. WCF – Lebenszyklus • WCF Services sind historisch-bedingt öfters Singletons

    • Komponenten einer (ASP).NET Core Anwendung sind meinstens "scoped" oder "transient" • Beachte: "scoped" Abhängigkeit darf nicht von Singletons verwendet werden (möglicher Memory Leak) • Angleichung des Lebenszykluses von WCF Services an Controller (transient) • Ermöglicht Nutzung aller Abhängigkeiten • Senkt Fehlerpotential, wenn WCF und Controller sich ähnlich verhalten • Lebenszyklus eines WCF-Services kann mithilfe eines IInstanceProvider gesteuert werden .NET 4, OWIN, WCF: Time to say goodbye Migration zu modernem serverseitigem .NET Gute Vorbereitung ist die halbe Miete namespace System.ServiceModel.Dispatcher; public interface IInstanceProvider { object GetInstance(InstanceContext instanceContext); object GetInstance(InstanceContext instanceContext, Message message); void ReleaseInstance(InstanceContext instanceContext, object instance); }
  23. AppDomains • Erstellen und Entladen von AppDomains wird nicht unterstützt

    • Ähnliches Verhalten gibt es mit AssemblyLoadContexts • In .NET 4 nicht unterstützt • Auch nicht mit NuGet-Paket System.Runtime.Loader (https://github.com/dotnet/runtime/issues/22732#issuecomment-415838808) .NET 4, OWIN, WCF: Time to say goodbye Migration zu modernem serverseitigem .NET Was lässt sich nicht vorbereiten?
  24. .NET 4, OWIN, WCF: Time to say goodbye Migration zu

    modernem serverseitigem .NET Migrationsansätze Empfehlenswerte Varianten aus Praxisprojekten
  25. Ansätze • Die Ansätze schließen sich gegenseitig nicht aus •

    Tipp: Falls ein NuGet-Paket kein plattform-unabhängiges .NET 8 (Moniker: net8.0) unterstützt, dann ggf. ein Windows-spezifisches (net8.0-windows)! • Migration wird somit in 2 Stufen vollzogen, zuerst zu net8.0-windows danach zu net8.0 • Zeigt Problemstellen auf ohne die Migration zu blockieren .NET 4, OWIN, WCF: Time to say goodbye Migration zu modernem serverseitigem .NET Migrationsansätze zur parallelen Weiterentwicklung Ansatz 1 Multi-Targeting Ansatz 2 Feature-Migration
  26. Multi-Targetting • Bauen der Anwendung für unterschiedliche Laufzeitumgebungen, in diesem

    Fall .NET 4 und .NET 8 • Keine Empfehlung für netstandard2.0: eingeschränkter Feature-Umfang und führt teilweise zu Assembly-Version Mismatches unter .NET 4 • Vorgehensweise: • Man fägt mit Projekten ohne Abhängigkeit und arbeitet sich hoch in Richtung Host-Projekt • Code für nur .NET 4 bzw. .NET 8 wird mithilfe von Conditional Compilation von einander abgegrenzt .NET 4, OWIN, WCF: Time to say goodbye Migration zu modernem serverseitigem .NET Migrationsansätze parallel zur Weiterentwicklung <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFrameworks>net48;net8.0</TargetFrameworks> </PropertyGroup> #if NETFRAMEWORK var appDomain = AppDomain.CreateDomain("name"); #else var ctx = new AssemblyLoadContext("name"); #endif
  27. Multi-Targetting (Vor-/Nachteile) • Vorteile: • Das Verhalten unter .NET 4

    bleibt unangetastet • Beide Frameworks können unterschiedliche NuGet-Packages referenzieren • Regelmäßige Reintegration des Codes in den Hauptentwicklungszweig möglich • Senkt Grad der Ungewissheit – Compiler deckt die meisten Probleme sofort auf • Wahlfreiheit, ob problematische Stellen sofort angegangen werden sollen oder später • Nachteile: • Weniger Effizient, weil die Code-Basis ggf. in mehreren Iterationen migriert wird • Erhöhte Wartungsaufwand aufgrund von Conditional Compilation .NET 4, OWIN, WCF: Time to say goodbye Migration zu modernem serverseitigem .NET Migrationsansätze zur parallelen Weiterentwicklung
  28. Migration von einzelnen Teilen der Anwendung • Für Anwendungsfälle bzw.

    Code mit wenigen Abhängigkeiten zum Rest der Anwendung und wenn der Shared State (Cache) eher gering ist • Vorteile: • Effizient, man fasst den Code nur einmal an • Nachteile: • Hoher Grad der Ungewissheit, wieviel sich (nicht) reibungslos migrieren lässt • Eingeschränkte Weiterentwicklung im Hauptentwicklungszweig • Jegliche Anpassungen müssen nachträglich auch migriert werden • Reintegration der partiell migrierte Anwendung ist nicht immer erwünscht - aber möglich, wenn die Deployment-Infrastruktur es erlaubt .NET 4, OWIN, WCF: Time to say goodbye Migration zu modernem serverseitigem .NET Migrationsansätze zur parallelen Weiterentwicklung
  29. Migration von einzelnen Teilen der Anwendung - Deployment • .NET

    8 Anwendung verarbeitet alle migrierten Endpunkte (MVC/Web API und WCF) • Reverse-Proxy als Fallback, welcher die Anfrage an .NET 4 Anwendung weiterleitet • Alternativ kann Reverse-Proxy vor .NET 8 stehen – führt jedoch zu komplexeren Konfiguration .NET 4, OWIN, WCF: Time to say goodbye Migration zu modernem serverseitigem .NET Migrationsansätze zur parallelen Weiterentwicklung .NET 8 Anwendung Reverse-Proxy (bspw. YARP) Endpunkt A (migriert) .NET 4 Anwendung Endpunkt B (legacy) Endpunkt C (legacy) HTTP-Anfrage
  30. .NET 4, OWIN, WCF: Time to say goodbye Migration zu

    modernem serverseitigem .NET OWIN und WCF Migrations Praxis Tipps
  31. OWIN Controller • Migrationsschritte nach einer guten Vorbereitung ☺ •

    Anpassung der Namespaces (System.Web.Http => Microsoft.AspNetCore.Mvc) • Ändere die Basisklasse von ApiController zu Controller • Bennene IHttpActionResult zu IActionResult um • Bei Datei-Uploads kann entweder IFormFile oder MultipartReader verwendet werden • Erfahrungsgemäß haben viele Probleme wenig bis gar nichts mit OWIN zu tun, sondern sind die Folge einer gewachsenen Architektur .NET 4, OWIN, WCF: Time to say goodbye Migration zu modernem serverseitigem .NET Migration von OWIN Controllers und WCF Services
  32. WCF • Server-Teil von WCF ist von Microsoft nach .NET

    8 nicht migriert worden • Alternative: CoreWCF • Existiert fast 4 Jahre, davon 2 Jahre als Pre-Release • Viele Konzepte, Interface und Klassen sind übernommen worden • Namespaces lauten CoreWCF.* anstatt System.ServiceModel.* • Beachte: einige Typen gibt es nun doppelt, bspw. • System.ServiceModel.OperationContractAttribute und • CoreWCF.OperationContractAttribute • Bettet sich in die ASP.NET Core Pipeline ein, d.h. vieles Features, wie die Authentifizierung kriegt man geschenkt .NET 4, OWIN, WCF: Time to say goodbye Migration zu modernem serverseitigem .NET Migration von OWIN Controllers und WCF Services
  33. CoreWCF • Setup eines WCF Services mit HttpBasicBinding (NuGet-Paket: CoreWCF.Http)

    .NET 4, OWIN, WCF: Time to say goodbye Migration zu modernem serverseitigem .NET Migration von OWIN Controllers und WCF Services var builder = WebApplication.CreateBuilder(); builder.Services .AddServiceModelServices() .AddServiceModelMetadata(); builder.Services.AddTransient<IService, Service>(); var app = builder.Build(); app.UseServiceModel(b => { b.AddService<IService>() .AddServiceEndpoint<IService, IService>( new BasicHttpBinding(), "/service"); }); app.Run(); [ServiceContract] public interface IService { [OperationContract] string Ping(); } public class Service : IService { public string Ping() { return "ok"; } }
  34. gRPC • gRPC wird oft als Ersatz für WCF empfohlen

    • Aber, erfahrungsgemäß wurde WCF genommen, weil damals nichts anderes (wie Web API) gab • Vorteile gehen teilweise verloren bei Kommunikation (über gRPC-Web) mit JS-basierten Apps • Kundenzitat: Wir sind auf gRPC umgestiegen, weil MSDN dies vorschlägt... • Wechsel zu gRPC ist eher eine Neuentwicklung als Migration • Es sei denn, man verwendet Code First Ansatz anstatt Contract First • Aber, man sollte ggf. Sinnhaftigkeit des Ansatzes in Frage stellen (vielleicht wegen Protobuf, Performance, etc.?) • Liefert allerdings keine Lösung für WCF-Behaviors und Co. • Nicht vergessen, die Clients müssen auch angepasst werden .NET 4, OWIN, WCF: Time to say goodbye Migration zu modernem serverseitigem .NET Migration von OWIN Controllers und WCF Services
  35. Erkenntnisse • Gute Vorbereitung ist entscheidend • Wähle passenden Migrationsansatz

    Ressourcen • CoreWCF: https://github.com/CoreWCF/CoreWCF • YARP: https://microsoft.github.io/reverse-proxy/index.html Frag mich @pawelgerr [email protected] .NET 4, OWIN, WCF: Time to say goodbye Migration zu modernem serverseitigem .NET