HTTP-Kommunikation ist Standard. Das gilt sowohl für den Browser, als auch für die allermeisten Services, die derzeit gebaut werden. Ebenfalls längst Standard ist die Komprimierung des Response – sofern der anfragende Client das auch unterstützt. Doch wie sieht es mit dem Request aus? Ich stoße in meinen Projekten gelegentlich auf Szenarien, bei denen es auch große Requests gibt, die schnell übertragen werden müssen. Insbesondere bei langsamen Übertragungswegen stößt man hier schnell auf Probleme. Request-Komprimierung kann an dieser Stelle für eine deutliche Steigerung der Performance sorgen. In C# gibt es im Standard beim HttpClient leider keinen Schalter, um eine Request-Komprimierung zu aktivieren. Man muss also selbst Hand anlegen. In diesem Post möchte ich einen eleganten Weg zeigen, um genau das zu erreichen.
Blog
Als .NET Entwickler auf dem MacBook Pro
Vor etwas über zwei Jahren startete ich für mich persönlich ein Experiment. Ich habe mir einen MacBook Pro mit dem zu der Zeit neuen M1 Prozessor gekauft. Für mich war das tatsächlich ein großer Schritt, da ich meinen Fokus auf der .NET Plattform von Microsoft habe und damit seit über 15 Jahren bis auf wenige Linux-Ausflüge primär auf Windows unterwegs war. Der neue M1 Prozessor und dessen Balance aus Leistung und Akkulaufzeit war dabei ein Auslöser der Entscheidung für das Experiment. Es kamen aber auch andere Faktoren dazu. Immer häufiger bin ich etwa bei Kunden und im Bekanntenkreis auf macOS Benutzer gestoßen. Die Zeit war also mehr als reif, mich selbst als Entwickler mit der Plattform zu beschäftigen. Über meine Erfahrungen, Ärgernisse und warum es für mich Stand heute eine gute Entscheidung war, erfährst du mehr in diesem Artikel.
Automatische Integrations- und Systemtests mit Testcontainers
Im letzten Artikel [1] haben wir uns mit automatischen Integrationstests mit ASP.NET Core beschäftigt. In diesem Artikel baue ich darauf auf und ergänze das Thema um eine sehr spannende Variante zum Mocking fremder Services. Die meisten Entwickler kennen das Problem. Sobald man auf der Integrations- oder Systemtestebene testen möchte, muss man sich über die Abhängigkeiten zu anderen Services Gedanken machen. Das fängt bereits bei der Datenbank an und hört dort leider nicht auf. Es geht i. d. R. auch um andere Services, die während des Testens benötigt werden. Zur Lösung des Problems gibt es grundsätzlich zwei Varianten: Man bindet externe Services während des Tests an oder man versteckt sie hinter einer Schnittstelle und baut einen Mock darum. Die erste Variante ist zwar realitätsnäher, hat aber einige gewichtige Nachteile. So ist die Laufzeit von Tests länger, man hängt vom Status eines externen Service ab und mehrere, konkurrierend laufende Tests können zum Problem werden. Mit Testcontainers können wir die meisten dieser Nachteile Streichen. Wie genau erkläre ich in diesem Artikel.
Automatische Integrationstests mit ASP.NET Core
Softwaretest ist ein Thema, was jeden Softwareentwickler stets begleitet. Wenn es um Testautomatisierung geht, erhalten wir dazu ein breites Set an Werkzeugen in die Hand gedrückt. Das geht bei Testframeworks wie xUnit los und geht über die Integration solcher Frameworks in moderne IDEs wie Visual Studio und Rider weiter. In diesem Beitrag möchte ich mir eines dieser Werkzeuge herauspicken und ins Rampenlicht rücken: Es geht um Integrationstests mit ASP.NET Core. Warum? Genau diese Art von Tests hat einen sicheren Platz in meinem Werkzeugkoffer eingenommen. Es passt sehr gut zu der Art, wie ich Testautomatisierung und das Thema Testpyramide / Testdiamant schon seit sehr langer Zeit sehe (mehr dazu unter [1]). Ich setze bei Testautomatisierung i. d. R. mehr auf einen sog. „Testdiamanten“, als auf eine „Testpyramide“. Dafür gibt es viele Gründe. Ein wichtiger ist, dass damit das Verhalten einer Softwarekomponente auf einer höheren Ebene getestet und damit festgezogen wird. So viel möchte ich jetzt aber nicht über die Gründe schreiben, sondern jetzt zum Thema des Artikels kommen.
Protobuf Nachrichten kompatibel erweitern
Im letzten Blogartikel habe ich Protobuf als Serialisierungsformat vorgestellt [1]. In diesem Artikel möchte ich mich mit einem Thema beschäftigen, auf das man im Laufe eines Projekts früher oder später kommt: Wie erweitere ich eine Protobuf Nachricht so, dass die Änderung kompatibel zur vorherigen Version der Nachricht bleibt? Diese Frage taucht typischerweise dann auf, wenn eine zu ändernde Nachricht zwischen zwei oder mehr Services ausgetauscht wird, diese Services bei einem Update aber nicht gleichzeitig aktualisiert werden (können). Nehmen wir ein einfaches Beispiel: Ich möchte in neues Feld in einem Nachrichtentyp hinzufügen. Zunächst mache ich das am Service, welcher die Nachricht sendet und etwas später mache ich das bei den empfangenden Services. Geht das einfach so? Diese und weitere ähnliche Fragen möchte ich mit diesem Artikel beantworten. Ich beziehe mich bei den Beispielen ausschließlich auf C# und die Protobuf Implementierung im Paket Google.Protobuf.
Protobuf in C# serialisieren und deserialisieren
Es gibt eine lange Liste von Formaten, welche für die Serialisierung und Deserialisierung von .NET Objekten verwendet werden kann. Xml und Json sind dabei lediglich die populärsten Vertreter. In diesem Artikel möchte ich mich mit Protobuf (oder ausgeschrieben „Protocol Buffers“) beschäftigen. Protobuf ist ein Format von Google. Es ist auf Performance und möglichst wenig Platzverbrauch ausgelegt. Zudem gibt es Unterstützung für viele verschiedene Programmiersprachen – C# ist nur eine davon. Protobuf lässt sich mit den Bibliotheken von Google in Java, Python, Objective-C, C++, Kotlin, Dart, Go, Ruby, PHP und natürlich C# verwenden. Es findet auch im Protokoll gRPC Verwendung. Letzteres ist einer der Gründe, warum ich mich mit Protobuf mehr in der Tiefe beschäftigt habe. Schließlich interessiert mich nicht nur die Serialisierung selbst oder Sachen wie die Performance, sondern auch wie mit Kompatibilitätsthemen (neue Felder, umbenannte Felder, etc.) umgegangen wird. In diesem Artikel schauen wir uns diese Themen anhand zweier alternativer Bibliotheken an. Diese sind Google.Protobuf von Google und protobuf-net von Marc Gravell.
Testautomatisierung mit Avalonia
Testautomatisierung auf UI Ebene ist häufig nicht so einfach zu erreichen. Grund dafür können technische Fragestellungen sein. So gilt es, auf irgendeine Art das Rendering des UI-Frameworks abzubilden. Ebenso gilt es, mögliche Usereingaben zu emulieren oder Eingabeelemente an der UI zu identifizieren. Auch zeitliche Aspekte spielen mit rein, so ist ein „Warte eine Sekunde…“ in einem automatisierten Test i. d. R. eine eher schlechte Idee. Doch es gibt auch Herausforderungen, die aus den Testfällen selbst entstehen. Versucht man etwa, ein Drag-Drop Verhalten automatisiert zu testen, beißt man sich dabei schon mal gerne die Zähne aus. Ich persönlich versuche UI Tests daher auf einem niedrigen Level zu halten, setze sie also primär für einfach zu überblickende Geradeausfälle ein. Mit Avalonia habe ich UI Tests zuletzt bei meinem Nuget-Paket RolandK.AvaloniaExtensions [1] eingesetzt. Hier ging es mir darum, dass die dort definierten Basisklassen und Features wie die Dependency Injection einwandfrei in einer Avalonia Applikation funktionieren.
Avalonia FluentTheme zur Laufzeit wechseln
Viele moderne Applikationen bieten neben einer ansprechenden UI auch den Wechsel zwischen verschiedenen Themes an. Für gewöhnlich wird zumindest zwischen Hell und Dunkel unterschieden. Gleiches gilt für das Betriebssystem selbst – Windows und macOS bieten dem User jeweils die Wahl zwischen Hell und Dunkel. Auch Avalonia bietet mit dem FluentTheme seit Version 0.10 einen sehr einfachen Weg an, zwischen hellen und dunklen Modus zu unterscheiden. Typischerweise wird das FluentTheme in der App.xaml angegeben und bekommt als Mode entweder „Light“ oder „Dark“. In diesem Artikel wollen wir uns damit beschäftigen, wie diese Einstellung zur Laufzeit der Applikation verändert werden kann. Weiterhin schauen wir uns an, wie man unter Windows den aktuell konfigurierten Theme herausbekommt und sogar auf Änderung des aktuellen Theme reagieren kann.
Avalonia Applikationen übersetzen
In den letzten Monaten habe ich vermehrt Artikel über das Cross-Platform Framework Avalonia geschrieben. Für mich persönlich hat sich das Framework mittlerweile zum Standard für Desktop-Applikationen entwickelt. Es kann fast alles, was man braucht und läuft auf allen gängigen Desktop Plattformen (Windows, macOS, Linux) stabil. In diesem Artikel möchte ich mich mit einem Thema beschäftigen, auf das die meisten Softwareentwickler bei UIs irgendwann stoßen: Applikationen in andere Sprachen übersetzen. Auch wenn man nicht den akuten Bedarf hat, so sollte man UIs möglichst von vorne herein darauf vorbereiten, dass sie übersetzbar sind. Übersetzung im Nachhinein einzubauen kann häufig sehr schwierig sein. Insbesondere, wenn Daten von außen bereits behaftet mit einer bestimmten Sprache in der eigenen Applikation ankommen.
Yaml Dateien mit C# parsen
Es gibt eine lange Liste von verbreiteten Markup-Formaten. Xml und Json sind dabei den allermeisten Entwicklern ein Begriff. Auch Yaml ist ein Format, welches nicht zuletzt durch den Einsatz bei Kubernetes oder anderen bekannten Applikationen eine größere Verbreitung genießt. Yaml wirkt auf den ersten Blick wie ein „Json ohne Klammern“. Das habe ich selbst tatsächlich auch lange so angenommen. Beschäftigt man sich etwas tiefer im Detail mit Yaml, so wird man aber schnell eines Besseren belehrt. Yaml bietet mehrere Features und hat etwa bei der Ermittlung der Datentypen ein mehr oder weniger komplexes Regelwerk. Aber warum überhaupt Yaml, wenn man doch auch Json einsetzen könnte? Yaml-Dateien könnten leichter durch einen Menschen geschrieben und gelesen werden. Aus diesem Grund wird es gerne für Konfigurationsdateien verwendet – so wie etwa bei Kubernetes. Somit kann es auch für C# Entwickler sinnvoll sein, anstelle von Json oder Xml eben Yaml für Konfigurationsdateien zu verwenden. Aus diesem Grund möchte ich mich in diesem Artikel mit dem Parsen von Yaml Dateien mit C# beschäftigen.