Slide 1

Slide 1 text

.NET 4, OWIN, WCF: Time to say goodbye Migration zu modernem serverseitigem .NET Pawel Gerr @pawelgerr Consultant

Slide 2

Slide 2 text

• 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

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

.NET 4, OWIN, WCF: Time to say goodbye Migration zu modernem serverseitigem .NET Migrationsmotivation Vorteile und Effekte des Wechsels auf modernes .NET 8

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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()

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

.NET 4, OWIN, WCF: Time to say goodbye Migration zu modernem serverseitigem .NET Migrationsvorbereitung Migration optimal vorbereiten

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

Umstellung auf SDK-basierte Projekte .NET 4, OWIN, WCF: Time to say goodbye Gute Vorbereitung ist die halbe Miete Debug AnyCPU Exe v4.8.1 Exe net4.8 Migration zu modernem serverseitigem .NET

Slide 14

Slide 14 text

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 Exe net4.8 12 Migration zu modernem serverseitigem .NET

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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().SingleInstance(); containerBuilder.RegisterType().SingleInstance(); using var container = containerBuilder.Build(); using var scope = container.BeginLifetimeScope(); // Case 1 var parent = scope.Resolve(); Console.WriteLine(parent.Child.Value); // 0 // Case 2 var factory = scope.Resolve>(); var nonSingletonChild = new Child { Value = 1 }; var nonSingletonParent = factory(nonSingletonChild); Console.WriteLine(nonSingletonParent.Child.Value); // 1 var parent = scope.Resolve(); Console.WriteLine(parent.Child.Value); // ? Tipp: Es ist nicht 0

Slide 19

Slide 19 text

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(); } }

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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); }

Slide 23

Slide 23 text

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?

Slide 24

Slide 24 text

.NET 4, OWIN, WCF: Time to say goodbye Migration zu modernem serverseitigem .NET Migrationsansätze Empfehlenswerte Varianten aus Praxisprojekten

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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 net48;net8.0 #if NETFRAMEWORK var appDomain = AppDomain.CreateDomain("name"); #else var ctx = new AssemblyLoadContext("name"); #endif

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

.NET 4, OWIN, WCF: Time to say goodbye Migration zu modernem serverseitigem .NET OWIN und WCF Migrations Praxis Tipps

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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(); var app = builder.Build(); app.UseServiceModel(b => { b.AddService() .AddServiceEndpoint( new BasicHttpBinding(), "/service"); }); app.Run(); [ServiceContract] public interface IService { [OperationContract] string Ping(); } public class Service : IService { public string Ping() { return "ok"; } }

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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