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
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
• 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
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()
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
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
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
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
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
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
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
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
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(); } }
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
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
• 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); }
• Ä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?
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
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
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
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
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
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
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
.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"; } }
• 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