Die asynchrone Datenbindung in Blazor, insbesondere bei der Arbeit mit Web-APIs, stellt einen zentralen Aspekt moderner Webentwicklung dar. Sie erlaubt es, Daten dynamisch und effizient aus entfernten Quellen abzurufen und in UI-Komponenten zu binden, ohne die Benutzererfahrung durch langes Warten oder Blockieren des Interfaces zu beeinträchtigen.

In dem gezeigten Beispiel wird mit einem HttpClient gearbeitet, der über eine Factory erzeugt wird. Dies entspricht der empfohlenen Praxis in Blazor, da es eine zentrale Konfiguration und Wiederverwendung ermöglicht. Die eigentliche Logik befindet sich in der Methode OnParametersSetAsync, welche bei jeder Parameteränderung der Komponente automatisch aufgerufen wird. Durch die Verwendung des async/await-Musters bleibt die Benutzeroberfläche responsiv, während die Daten geladen werden.

Ein bedeutender Aspekt dieses Codes ist die Nutzung spezieller JsonSerializerOptions, insbesondere mit dem ReferenceHandler.Preserve. Dies ist notwendig, wenn Datenstrukturen zirkuläre Referenzen enthalten, was beim Serialisieren und Deserialisieren ohne diese Option zu Laufzeitfehlern führen kann. Damit wird eine konsistente Referenzbehandlung zwischen Client und Server gewährleistet.

Die geladenen Daten – eine Liste von Mitarbeitern, Ländern und Städten – werden direkt über die Web-API geladen und in Feldern gespeichert, die anschließend über Datenbindung im UI verwendet werden können. Die Konvertierung zu IQueryable erlaubt dabei eine spätere effiziente Weiterverarbeitung, zum Beispiel für Filter- oder Suchoperationen innerhalb der UI-Komponente. Das ist besonders bei größeren Datenmengen ein Vorteil.

Auffällig ist die Behandlung möglicher Ausnahmen während der HTTP-Anfragen: Ein einfacher try-catch-Block fängt Fehler ab, loggt sie jedoch nur über die Konsole. Das genügt in einer Entwicklungsumgebung, ist aber für produktive Anwendungen nicht ausreichend. Eine differenzierte Fehlerbehandlung mit Feedback an den Benutzer ist hier essenziell.

Ein weiteres interessantes Detail ist der eventbasierte Umgang mit Eingaben im UI: Die Methode OnChange deutet darauf hin, dass bestimmte Eingabefelder oder Auswahlkomponenten Veränderungen des Benutzers abfangen und diese verarbeiten. Die genaue Implementierung ist nicht sichtbar, aber es ist ersichtlich, dass die Methode einen generischen Ansatz verfolgt – value kann ein beliebiger Typ sein, wird jedoch offenbar oft als IEnumerable behandelt, was auf mehrfache Auswahl (z. B. bei Dropdowns) hinweist.

Ein weiteres zentrales Thema ist die initiale Nullbarkeit aller verwendeten Datenstrukturen. Das lässt erkennen, dass hier ein defensiver Programmierstil verfolgt wird, um Nullreferenzfehler im Laufe der Datenbindung zu vermeiden. Das ist im Zusammenspiel mit async-Ladevorgängen besonders wichtig, da die UI jederzeit in einem Zustand sein kann, in dem die Daten noch nicht verfügbar sind.

Wichtig ist zu verstehen, dass der Zugriff auf APIs nicht nur die Datenlieferung betrifft, sondern auch stark mit Serialisierungsstrategien, Fehlerhandling und Lebenszyklusereignissen in Blazor-Komponenten verflochten ist. Asynchrone Methoden wie OnParametersSetAsync sind dabei mehr als bloße Datenlader – sie sind ein zentraler Ort, an dem die Brücke zwischen dem statischen Layout und dynamischen Datenflüssen geschlagen wird.

Beim Umgang mit JSON-Daten im Blazor-Client ist besondere Vorsicht geboten, wenn es um komplexe Objekte geht, die möglicherweise in .NET über Referenzschleifen verfügen. Ohne korrekt gesetzte JsonSerializerOptions kann dies zu Deserialisierungsfehlern führen, die schwer zu diagnostizieren sind. Die Verwendung von ReferenceHandler.Preserve erfordert aber auch, dass der Server entsprechend serialisiert – andernfalls kann es zu Inkompatibilitäten kommen. Diese Feinheiten müssen zwischen Client und Server präzise abgestimmt sein.

Außerdem sollte beachtet werden, dass bei häufiger Verwendung von HttpClient-Aufrufen in Komponenten eine klare Trennung zwischen UI-Logik und Datenzugriff erfolgen sollte. Das bedeutet im Idealfall die Auslagerung des API-Zugriffs in separate Services, um die Wiederverwendbarkeit, Testbarkeit und Lesbarkeit des Codes zu verbessern.

Insgesamt ist das Verständnis des asynchronen Komponentenlebenszyklus, der API-Kommunikation sowie der Serialisierungsdetails entscheidend, um robuste und wartbare Blazor-Anwendungen zu entwickeln.

Wie man das MVVM Toolkit in .NET MAUI für die Arbeit mit Kategorien integriert

Das MVVM (Model-View-ViewModel) Toolkit ist ein mächtiges Werkzeug, das Entwicklern hilft, die Trennung von Präsentationslogik und Geschäftslogik in einer Anwendung zu gewährleisten. Es reduziert den Codeaufwand und erleichtert das Testen, indem es eine klare Trennung der Verantwortlichkeiten zwischen den verschiedenen Komponenten der Anwendung bietet. Im folgenden Abschnitt erfahren wir, wie das MVVM Toolkit in einer .NET MAUI-Anwendung integriert wird, um mit einer Web-API für Kategorien zu arbeiten.

Zunächst müssen wir sicherstellen, dass die erforderlichen Pakete im Projekt hinzugefügt werden. Im Projekt „Northwind.Maui.Blazor.Client“ müssen die entsprechenden Paketreferenzen für das .NET MAUI Community Toolkit und das MVVM Community Toolkit eingebunden werden. Nachdem dies erledigt ist, wird das Projekt gebaut, um die Pakete zu installieren. Ein Hinweis, der dabei erscheint, bezieht sich auf einen Code-Analyzer des .NET MAUI Community Toolkits, der sicherstellt, dass die Erweiterungsmethode des Toolkits verwendet wurde. Dies wird im nächsten Schritt durch einen entsprechenden Aufruf in der Datei „MauiProgram.cs“ umgesetzt.

Im „MauiProgram.cs“-Datei muss der folgende Code eingefügt werden, um das .NET MAUI Community Toolkit zu aktivieren:

csharp
var builder = MauiApp.CreateBuilder();
builder .UseMauiApp() .UseMauiCommunityToolkit() .ConfigureFonts(fonts => { fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); });

Nun zum Modell und ViewModel für die Arbeit mit den Kategorien. In der Ordnerstruktur „Views/Categories“ wird eine neue Klasse „Category.cs“ erstellt, die das MVVM Community Toolkit nutzt, um ein beobachtbares Modell zu implementieren. Das Modell ist mit der „Category“-Entität aus einer SQL Server EF Core-Datenbank verknüpft und hat eine zusätzliche Eigenschaft für das Bild der Kategorie. Anstelle der Bilddaten, die als Bytes gespeichert sind, wird hier ein Pfad zum Bild verwendet.

Die Klasse „Category.cs“ sieht wie folgt aus:

csharp
using CommunityToolkit.Mvvm.ComponentModel; namespace Northwind.Maui.Blazor.Client.Views.Categories;
internal partial class Category : ObservableObject
{ [
ObservableProperty] [NotifyPropertyChangedFor(nameof(PicturePath))] private int categoryId; [ObservableProperty] private string categoryName; [ObservableProperty] private string description; [ObservableProperty] private byte[] picture; [ObservableProperty] private string picturePath; }

Die „PicturePath“-Eigenschaft folgt einem Muster, bei dem der Dateiname auf dem Kategorie-ID basiert, zum Beispiel „categoryX_small.jpeg“, wobei „X“ die Kategorie-ID darstellt. Wenn sich die Kategorie-ID ändert, muss der Code sicherstellen, dass alle gebundenen Daten ebenfalls aktualisiert werden.

Im nächsten Schritt erstellen wir eine ViewModel-Klasse „CategoriesViewModel.cs“, die von „ObservableCollection<Category>“ erbt. Diese ViewModel-Klasse wird für das Abrufen der Kategorien von einem Web-Service und deren Verwaltung verantwortlich sein. Die Kategorien werden über eine HTTP-Anfrage abgerufen, und nach erfolgreichem Laden werden sie in einer ObservableCollection gespeichert. Es gibt auch einige Befehle, wie zum Beispiel „AddCategoryToFavorites“ und „DeleteCategory“, die mit der Benutzeroberfläche interagieren.

Die Klasse „CategoriesViewModel.cs“ könnte folgendermaßen aussehen:

csharp
using CommunityToolkit.Mvvm.Input;
using System.Collections.ObjectModel; using System.Net.Http.Headers; using System.Net.Http.Json; namespace Northwind.Maui.Blazor.Client.Views.Categories; internal partial class CategoriesViewModel : ObservableCollection<Category> { public string InfoMessage { get; set; } = string.Empty;
public string ErrorMessage { get; set; } = string.Empty;
public bool ErrorMessageVisible { get; set; } public CategoriesViewModel() { try { HttpClient client = new() {
BaseAddress = new Uri(DeviceInfo.Platform == DevicePlatform.Android ? "http://10.0.2.2:5192" : "http://localhost:5192")
}; InfoMessage =
$"BaseAddress: {client.BaseAddress}. "; client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); HttpResponseMessage response = client.GetAsync("api/categories").Result; response.EnsureSuccessStatusCode(); IEnumerable<Category> categories = response.Content.ReadFromJsonAsync<IEnumerable<Category>>().Result; foreach (Category category in categories) { int offset = 78; // OLE Header entfernen category.Picture = category.Picture.AsSpan(offset, category.Picture.Length - offset).ToArray(); category.PicturePath = $"category{category.CategoryId}_small.jpeg"; Add(category); } InfoMessage += $"{Count} categories loaded."; } catch (Exception ex) { ErrorMessage = ex.Message; ErrorMessageVisible = true; } } [RelayCommand] private void AddCategoryToFavorites() { Console.WriteLine("Add category to favorites"); } [RelayCommand] private void DeleteCategory() { Console.WriteLine("Delete category"); } }

Das Abrufen der Kategorien von der Web-API ist eine der zentralen Aufgaben dieses ViewModels. Es ist wichtig, die Fehlerbehandlung ordnungsgemäß durchzuführen, da Netzwerkfehler oder andere Probleme beim Abrufen der Daten auftreten können. In solchen Fällen wird eine Fehlermeldung angezeigt.

Um die Kategorien schließlich in der Benutzeroberfläche darzustellen, können wir die XAML-Datei „CategoriesPage.xaml“ anpassen. Zuerst müssen die erforderlichen Namensräume importiert werden. Dann erstellen wir eine Instanz des ViewModels und binden es an die Seite, um die Daten anzuzeigen. Ein Carousel mit den Kategorien sowie die Anzeige von Fehlermeldungen und Informationen zum Web-Service-Endpunkt wird auf der Seite angezeigt.

Wichtig ist es zu beachten, dass die Verwendung von MVVM nicht nur dazu dient, den Code übersichtlich und wartbar zu halten, sondern auch eine engere Kopplung zwischen der Benutzeroberfläche und den zugrunde liegenden Daten zu verhindern. Diese Trennung ist besonders in größeren Anwendungen von Bedeutung, da Änderungen am UI-Design ohne Auswirkungen auf die Geschäftslogik vorgenommen werden können. Das MVVM-Muster fördert die Wiederverwendbarkeit von Komponenten und vereinfacht das Testen von ViewModels, da diese unabhängig von der Benutzeroberfläche getestet werden können.

Wie man CORS-Probleme in einer Webanwendung löst und den Zugriff von JavaScript auf Web-APIs ermöglicht

Die Entwicklung von Webanwendungen, die APIs ansprechen, ist eine gängige Praxis in der modernen Softwareentwicklung. Dabei stellen sich häufig Herausforderungen, insbesondere wenn es um die Kommunikation zwischen verschiedenen Diensten auf unterschiedlichen Ports geht. Ein besonders häufiges Problem ist die Cross-Origin Resource Sharing (CORS)-Politik, die verhindern kann, dass JavaScript aus einer Webanwendung auf Ressourcen zugreift, die auf einem anderen Server oder Port gehostet werden. In diesem Abschnitt werden wir sehen, wie man eine Webanwendung erstellt, die ein Webservice über JavaScript anspricht, und wie man CORS-Probleme richtig handhabt.

Wenn wir ein einfaches Beispiel mit einer ASP.NET Core-Anwendung und einem separaten Webservice aufbauen, könnte der erste Schritt die Konfiguration der verschiedenen Projekte sein. Ein neues Projekt mit dem Template "ASP.NET Core Web App (Model-View-Controller)" kann erstellt werden. In Visual Studio wird das Projekt mit den entsprechenden Einstellungen eingerichtet: HTTPS aktivieren, Docker deaktivieren und sicherstellen, dass keine Top-Level-Anweisungen verwendet werden. Danach wird die URL des Webclients auf einen bestimmten Port konfiguriert, zum Beispiel auf https://localhost:5092.

Im nächsten Schritt erstellen wir eine einfache HTML-Seite mit einem Textfeld und einem Button, die es dem Benutzer ermöglichen, nach Produkten zu suchen. Dabei kommt JavaScript ins Spiel, das eine Anfrage an einen Webservice senden soll. Der Webservice soll dann eine Liste von Produkten zurückgeben, die einen bestimmten Namen enthalten. Wenn jedoch der Benutzer eine Anfrage auslöst, indem er beispielsweise „man“ in das Suchfeld eingibt und den Button „Get Products“ klickt, wird eine Fehlermeldung angezeigt: „Access to XMLHttpRequest at 'https://localhost:5091/api/products/man' from origin 'https://localhost:5092' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.“ Diese Fehlermeldung ist das Ergebnis der CORS-Richtlinien, die verhindern, dass Anfragen zwischen verschiedenen Ursprüngen (Ports) zugelassen werden.

Die Ursache des Problems ist, dass der JavaScript-Client und der Webservice auf unterschiedlichen Ports laufen, was dazu führt, dass der Browser eine "Cross-Origin"-Anfrage blockiert. Dies wird als eine Sicherheitsmaßnahme angesehen, um zu verhindern, dass bösartige Websites auf Ressourcen zugreifen, die für eine andere Domain bestimmt sind. Der Webservice selbst hat zwar auf die Anfrage reagiert und eine JSON-Antwort mit den Produkten gesendet, doch der Browser blockiert diese Antwort, da er die Anfrage als unsicher betrachtet.

An diesem Punkt stellt sich die Frage, wie man dieses Problem lösen kann. Eine Lösung ist es, die CORS-Politik auf dem Webservice so zu konfigurieren, dass er Anfragen von verschiedenen Ursprüngen akzeptiert. In ASP.NET Core kann dies durch die Verwendung des CORS-Middleware erfolgen. Diese Middleware ermöglicht es, spezifische Ursprünge zu erlauben und bestimmte HTTP-Methoden oder Header zuzulassen, die für den Zugriff auf die API erforderlich sind.

Die Konfiguration könnte etwa folgendermaßen aussehen:

csharp
public void ConfigureServices(IServiceCollection services)
{ services.AddCors(options => { options.AddPolicy("AllowSpecificOrigin", builder => builder.WithOrigins("https://localhost:5092") .AllowAnyMethod() .AllowAnyHeader()); }); }

Mit dieser Konfiguration wird dem Webservice mitgeteilt, dass er Anfragen von https://localhost:5092 akzeptieren soll, und zwar für alle HTTP-Methoden und Header, die benötigt werden. Dies löst das CORS-Problem und ermöglicht es dem JavaScript-Client, auf die API zuzugreifen.

Ein weiterer wichtiger Aspekt beim Arbeiten mit Webservices und APIs ist die Sicherheit. Es ist wichtig, dass beim Konfigurieren von CORS nicht zu viele Ursprünge zugelassen werden, um potenzielle Sicherheitslücken zu vermeiden. Beispielsweise sollte in einer Produktionsumgebung darauf geachtet werden, dass nur vertrauenswürdige Ursprünge erlaubt werden. Eine zu offene CORS-Konfiguration kann dazu führen, dass Angreifer auf Ihre API zugreifen und potenziell schadhafter Code ausgeführt wird.

Abgesehen von der CORS-Konfiguration müssen Webentwickler auch sicherstellen, dass der Webservice korrekt protokolliert, welche Anfragen er verarbeitet. Dies hilft, die Kommunikation zwischen Client und Server zu überwachen und Fehler zu erkennen. In unserem Beispiel könnte das HTTP-Logging für das Webservice-Projekt aktiviert werden, um die Anfragen und Antworten zu überwachen, die zwischen dem Webclient und der API ausgetauscht werden. So können wir feststellen, ob der Webservice tatsächlich die richtigen Daten zurückgibt und ob es andere Probleme gibt, die möglicherweise zur Blockierung der Anfrage führen.

Ein weiterer Punkt, der berücksichtigt werden sollte, ist die korrekte Fehlerbehandlung im Client. Während der Webservice die Daten möglicherweise korrekt liefert, kann es im JavaScript-Client zu weiteren Fehlern kommen, die eine ordnungsgemäße Anzeige der Informationen verhindern. Die Implementierung von Fehlerbehandlung und Benutzerbenachrichtigungen ist daher ein entscheidender Bestandteil einer benutzerfreundlichen Anwendung. Dies kann durch einfache try-catch-Blöcke oder durch das Abfangen von spezifischen HTTP-Fehlercodes wie 400 oder 500 erfolgen.

Abschließend lässt sich sagen, dass die Arbeit mit CORS und der Kommunikation zwischen verschiedenen Webdiensten eine gründliche Kenntnis der Websicherheit und der korrekten API-Konfiguration erfordert. Es ist unerlässlich, CORS korrekt zu konfigurieren, um den sicheren und effizienten Zugriff auf Web-APIs zu gewährleisten, während gleichzeitig die Sicherheit der Anwendung nicht gefährdet wird.