ASP.NET Core Blazor WebAssembly: Authentifizierung und Autorisierung mit IdentityServer in Aktion

Seit der Version Blazor WebAssembly 3.2.0 enthält Blazor umfangreiche Unterstützung für clientseitige Authentifizierung, wodurch die Implementierung von OpenID Connect und OAuth2 in Single-Page-Applications (SPAs) deutlich vereinfacht wird. In diesem Artikel sehen wir uns an, wie wir Authentifizierung und Autorisierung in einem Blazor-WebAssembly-Client realisieren können. Zusätzlich werden wir die Client UI auf Basis von Nutzerrechten entsprechend dynamisch anpassen.

In diesem Artikel:

Artikelserie

  1. Authentifizierung und Autorisierung mit IdentityServer in Aktion ⬅
  2. Authentifizierung und Autorisierung mit Keycloak in Aktion

Version Information:

  • ASP.NET Core Blazor: 3.2.0
  • ASP.NET Core: 3.1.3
  • IdentityServer 4
  • MatBlazor: 2.4.3

Anhand einer Demoapplikation wird nachvollziehbar, wie ein Blazor-WebAssembly-Client sich bei einem IdentityServer anmelden kann. Zusätzlich werden wir Informationen über den aktuellen Nutzer abfragen und nutzen, indem wir bestimmte Bereiche nur für autorisierte Nutzer zugänglich machen. Mit dem Access Token, den wir vom IdentityServer erhalten, können wir dann eine token-gesicherte Web-API aufrufen oder eine sichere SignalR-Verbindung aufbauen. Weitere Informationen über den IdentityServer oder die Konfiguration der Clients, Claims und Policies, finden sich in der IdentityServer-Dokumentation.

Der gesamte Source Code zu diesem Artikel befindet sich im zugehörigen GitHub Repository.

Authentifizierungsarchitektur in Blazor WebAssembly

Bevor wir darin einsteigen, eine Authentifizierung und Autorisierung im Blazor-Client zu implementieren, betrachten wir zuerst die Security-Architektur innerhalb von Blazor WebAssembly:

  • (1) Eingebettet in eine Razor-Seite wird im ersten Schritt die RemoteAuthenticatorView aufgerufen, die eine Aktion (z.B. login oder logout) entgegen nimmt.
  • (2) Anschließend nutzt diese Komponente den RemoteAuthenticationService, der als Brücke zwischen dem C#-Code und dem JavaScript-Code dient.
  • (3) Unter Verwendung der JsRuntime verwendet der RemoteAuthenticationService den AuthenticationService. Hier handelt es sich um eine JavaScript-Implementierung.
  • (4 & 5) Der AuthenticationService ruft in unserem Fall den IdentityServer auf, um sich über diesen zu authentifizieren und Tokens zurück zu erhalten.
  • (6 & 7) Ist das Ergebnis erfolgreich, speichert der AuthenticationService die Daten im Session Storage und gibt das Ergebnis zurück an den RemoteAuthenticationService.
  • (8 & 9) Zum Schluss teilt der RemoteAuthenticationService der RemoteAuthenticatorView mit, ob der Login erfolgreich war.

Blazor-Client erstellen und konfigurieren

Beim Erstellen eines neuen Blazor-WebAssembly-Projekts kann der Parameter -au angegeben werden. Er zeigt an, dass individuelle Benutzerkonten zur Authentifizierung genutzt werden sollen. Dies entspricht den notwendigen Voraussetzungen zur Nutzung von IdentityServer.

				
					# Erstellen einer Blazor-WASM-Applikation mit individuellen Nutzerkonten
dotnet new blazorwasm -au individual -n BlazorClient
				
			

Diese Einstellung sieht einen Platzhalter für die OpenID-Verbindungskonfiguration in der Datei Program.cs vor:

				
					public static async Task Main(string[] args)
{
  ...
  builder.Services.AddOidcAuthentication(options =>
  {
    // ... add options here
  });
  ...
}
				
			

An diesem Punkt können wir die Parameter konfigurieren, die für die Kommunikation mit IdentityServer erforderlich sind. Wir haben entweder die Möglichkeit, die Konfiguration direkt im Code zu hinterlegen, was für eine kurze Beispielimplementierung ausreichend ist, oder man verwendet für mehr Flexibilität eine Konfigurationsdatei. Dazu nutzen wir die vorhandene appsettings.json-Datei und fügen eine neue Konfiguration hinzu:

				
					{
  "Oidc": {
    "Authority": "https://localhost:5001/",
    "ClientId": "blazor-spa",
    "DefaultScopes": [
      "openid",
      "profile"
    ],
    "PostLogoutRedirectUri": "/",
    "ResponseType": "code"
  }
}
				
			

Folgende Parameter werden in der Konfigurationsdatei gesetzt:

  • Authority ist die URL des IdentityServers, die sowohl für die Umleitung als auch für die Überprüfung der Signatur der Tokens und der Identität, die sie ausgegeben hat, verwendet wird.
  • ClientId ist der eindeutige Name für die Anwendung.
  • DefaultScopes sind die Scopes, die wir während des Anmeldevorgangs anfordern möchten, wie z.B. die E-Mail-Adresse oder die Profilinformationen. Wir verwenden hier openid, um anzuzeigen, dass wir die Überprüfung der Identität des Benutzers mit OpenID Connect durchführen möchten, und profile, um einige grundlegende Informationen des Benutzers abzurufen, z.B. seinen Namen.
  • ResponseType ist der von uns verwendete Grant Type, hier der Authorization-Code-Grant.
  • PostLogoutRedirectUri URL, an die wir weitergeleitet werden wollen, sobald wir uns ausloggen.

Die von uns hinzugefügte Konfiguration übergeben wir dann an die ProviderOptions-Eigenschaft.

				
					builder.Services.AddOidcAuthentication(options =>
{
  builder.Configuration.Bind("Oidc", options.ProviderOptions);
});
				
			

Zum Schluss müssen wir die RemoteAuthenticatorView in einer Blazor-Page hinzufügen. Sie ist der zentrale Dreh- und Angelpunkt für die benutzerzentrierte Interaktion mit dem Authentifizierungssystem. Hierzu existiert in der Demoapplikation eine Seite Authentication.razor. Um nicht für jede Aktion eine neue Seite anlegen zu müssen, wird die gewünschte Aktion (wie loginoder logout) als Parameter an die Seite mit übergeben.

				
					@page "/authentication/{action}"

@using Microsoft.AspNetCore.Components.WebAssembly.Authentication

<RemoteAuthenticatorView Action="@Action" />

@code{
    [Parameter] public string Action { get; set; }
}
				
			

Auf der Startseite der Anwendung befindet sich ein Login-Button, der mit der Aktion login die Route auhentication/login aufruft und somit den Authentifizierungsprozess startet.

				
					@page "/"

@inject NavigationManager Navigation

<div style="display: flex; justify-content:center; align-items: center; height: 100%;">
    <MatButton OnClick="@BeginSignIn" Unelevated="true" Style="background-color: #ff584f;">Login</MatButton>
</div>

@code {
    private void BeginSignIn(MouseEventArgs args)
    {
        Navigation.NavigateTo("authentication/login");
    }
}
				
			

Nachdem wir nun eine erfolgreiche Authentifizierung des Clients am IdentityServer durchführen können, wollen wir uns im nächsten Schritt Nutzerdaten abrufen und verarbeiten.

Erweitern von und Arbeiten mit Informationen über den Benutzer

Über den ID-Token können wir auf die vom IdentityServer bereit gestellten Informationen über den Benutzer zugreifen. Für den Fall, dass für unsere Clientanwendung eine Information über den Benutzer zusätzlich in den Token inkludiert werden soll, wie zum Beispiel die E-Mail-Adresse, können wir diese neue Eigenschaft im IdentityServer hinzufügen. Dazu passen wir die Konfiguration für den Client an (Config.cs):

				
					public static IEnumerable<IdentityResource> IdentityResources =>
  new IdentityResource[]
  {
    new IdentityResources.OpenId(),
    new IdentityResources.Profile(),
    new IdentityResources.Email()
  };

public static IEnumerable<Client> Clients =>
  new Client[]
  {
    new Client
    {
      ClientId = "blazor-spa",
      AllowedScopes =
      {
          // Hier können neue Scopes hinzugefügt werden, welche vom Client dann abgerufen werden können
          IdentityServerConstants.StandardScopes.OpenId,
          IdentityServerConstants.StandardScopes.Profile,
          IdentityServerConstants.StandardScopes.Email
      },
      ...
    },
 };
				
			

Zusätzlich muss dieser anzufordernde Scope in der Konfiguration im Blazor-Client ergänzt werden:

				
					{
  "DefaultScopes": [
    "openid",
    "profile",
    "email"
  ]
}

				
			

Haben wir alle Anpassungen gemacht, sind die neue Benutzerinformation über den ID-Token abrufbar.

Nun können wir über die context-Eigenschaft der AuthorizeView auf die Daten des aktuellen Benutzers zuzugreifen. Dafür nutzen wir die User-Property. Diese beinhaltet die Daten des aktuellen Benutzers sowie den aktuellen Zustand, ob ein Nutzer authentifiziert ist oder nicht. Im Beispiel unten sehen wir, dass wir innerhalb der View mit Authorized Inhalte darstellen können, die nur authentifizierte Benutzer sehen, beispielsweise seinen Namen und den Logout-Button. Wenn die Authentifizierung nicht erfolgreich war oder der Authentifizierungsprozess noch nicht gestartet wurde, zeigen wir via NotAuthorized den Login-Button an. Darüber hinaus können wir mit dem context auf den aktuellen AuthenticationState zugreifen, der den aktuellen Benutzer mit all seinen Ressourcen kennt 

				
					<AuthorizeView>
    <Authorized>
        <p>@context.User.Identity.Name</p>
        <MatIconButton Icon="exit_to_app" OnClick="@BeginSignOut"></MatIconButton>
    </Authorized>
    <NotAuthorized>
        <MatButton OnClick="@BeginSignIn" Unelevated="true">Login</MatButton>
    </NotAuthorized>
</AuthorizeView>

				
			

Eine ähnliche Vorgehensweise können wir auch für ganze Seiten nutzen, in dem wir dort das Authorize-Attribut hinzufügen. Durch das Attribut kann die Seite nur durch einen authentifizierten Nutzer aufgerufen werden.

				
					@page "/history"
@attribute [Authorize]
				
			

Sicher mit dem Server kommunizieren

Aufrufen einer gesicherten Web-API

Nachdem wir in unserem Blazor-Client auf den aktuellen Authentifizierungsstatus zugreifen können, möchten wir jetzt Daten von einer sicheren Web-API abrufen. Hierzu müssen wir den vom IdentityServer erhaltenen Access Token beim Aufrufen der Web-API-Methode als HTTP-Header hinzufügen.

Blazor bietet hier den Handler AuthorizationMessageHandler an, der mithilfe von Dependency Injection bereitgestellt werden kann. Dieser schaut, ob ein Token vorhanden ist und fügt diesen bei jedem HTTP-Request als Authorization-Header hinzu. Hierfür benötigen wir einen Verweis auf das Microsoft.Extension.Http-NuGet-Paket. Danach verwenden wir die IHttpClientFactory, um einen HttpClient für unsere API zu registrieren.

				
					builder.Services.AddHttpClient("Blazor.API")
    .AddHttpMessageHandler(sp => 
    {
        var handler = sp.GetService<AuthorizationMessageHandler>()
            .ConfigureHandler(
                authorizedUrls: new[] { "http://localhost:5002" },
        return handler;
    });
				
			

Der obige Code definiert einen Client mit dem Namen Blazor.API, der intern den AuthorizationMessageHandler verwendet. In der Konfiguration tragen wir die authorizedUrls ein, die ein Access Token benötigen. Danach registrieren wir die Standard-HttpClient-Instanz im Dependency-Injection-Container:

				
					builder.Services
    .AddScoped(services => services.GetRequiredService<IHttpClientFactory>()
    .CreateClient("Blazor.ServerAPI"));
				
			

Fortan wird automatisch beim Aufrufen der Web-API ein Authorization-Header mit gesendet, über den das serverseitige Web-API (bzw. die Middleware in ASP.NET Core) den Token auslesen und validieren kann.

Absichern einer SignalR-Verbindung

Möchte man aus dem Blazor-Client eine sichere SignalR-Verbindung mit einem Server aufbauen, muss auch hier der Token mitgesendet werden. Hierzu müssen wir zuerst unsere SignalR-Verbindung konfigurieren. Mithilfe der Klasse HubConnectionBuilder können wir eine Instanz einer HubConnection erstellen und konfigurieren.

				
					public class SignalRService 
{
    private IAccessTokenProvider _tokenProvider;
    // ...
    public async Task InitConnectionAsync()
    {
        // ...
        var accessTokenState = await _tokenProvider.RequestAccessToken();
        if (accessTokenState.TryGetToken(out var accessToken)) 
        {
            var apiBaseUrl = _configuration["api:baseUrl"];
            var accessTokenString = accessToken.Value;
            _hubConnection = new HubConnectionBuilder()
                .WithUrl($"{apiBaseUrl}tictactoe", options =>
                { 
                    options.AccessTokenProvider = () => Task.FromResult(accessTokenString);
                })
                .WithAutomaticReconnect(new[] { TimeSpan.Zero, TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(10) })
                .Build();
            //...
        }
    }
}
				
			

Die Übergabe des Tokens an die SignalR-Verbindung findet mithilfe eines IAccessTokenProviders statt. Der IAccessTokenProvider wird über Dependency Injection der Klasse SignalRService verfügbar gemacht. Dieser gibt den aktuellen Access Token zurück, der danach beim Aufbauen der Verbindung mitgesendet wird.

Im folgenden Bild sehen wir eine bestehende WebSocket-Verbindung, welche den Token als Parameter mit an den Server sendet.

Hinweis: Das Token wird nur beim initialen Aufbau der Verbindung überprüft und gilt dann für die gesamte Lebenszeit der Verbindung.

Mehr über SignalR gibt es hier in meinem Artikel zu Echtzeitkommunikation in Aktion zum Nachlesen.

Nun kann der Client eine sichere Verbindung zum serverseitigen Hub aufbauen und sich ordnungsgemäß authentifizieren.

Arbeiten mit Rollen

Rollen im IdentityServer und in der API konfigurieren

Nachdem wir uns mit unserem Client authentifiziert haben, möchten wir uns mit dem Thema Autorisierung beschäftigen. Ist ein Nutzer nur für einen bestimmten Bereich in der Anwendung berechtigt, kann dies über Rollen geregelt werden. Diese müssen natürlich zuerst im IdentityServer konfiguriert werden.

Hierzu schauen wir uns die Klasse ProfileWithRoleIdentityResource im IdentityServer an, die die gewünschten UserClaims definiert:

				
					public class ProfileWithRoleIdentityResource
        : IdentityResources.Profile
{
    public ProfileWithRoleIdentityResource()
    {
        this.UserClaims.Add(JwtClaimTypes.Name);
        this.UserClaims.Add(JwtClaimTypes.Subject);
        this.UserClaims.Add(JwtClaimTypes.WebSite);
        this.UserClaims.Add(JwtClaimTypes.Email);
        
        // Um die Rollen dem Identity Token hinzuzufügen, fügen wir den neuen Claim Role hier hinzu
        this.UserClaims.Add(JwtClaimTypes.Role);
    }
}
				
			

Hier ergänzen wir einen Claim des Typs Role hinzu. Durch diesen Claim können dem ID-Token Informationen über die Rollen des Benutzers hinzugefügt werden.

Im nächsten Schritt fügen wir den Claim Role auch bei den ApiResources hinzu, bei denen diese Information benötigt wird.

				
					public static IEnumerable<ApiResource> Apis =>
    new ApiResource[]
    {
        new ApiResource
        {
            // ...
            UserClaims =
            {
                JwtClaimTypes.Name,
                JwtClaimTypes.Subject,
                // Hier fügen wir den neuen UserClaim für die Rollen hinzu
                JwtClaimTypes.Role
            },
            //...
        },
    };
				
			

Als letztes benötigt unser Testbenutzer im IdentityServer die Information über seine Rollen. Hierzu fügen wir in der Datei TestUser.cs zum Testen nur einem Benutzer eine Rolle hinzu. Die anderen Benutzer bekommen keine Rolle, sodass wir im Client später einen Unterschied erkennen können.

				
					public class TestUsers
    {
        public static List<TestUser> Users = new List<TestUser>
        {
            new TestUser
            {
                SubjectId = "818727", Username = "alice", Password = "alice",
                Claims =
                {
                    new Claim(JwtClaimTypes.Name, "Alice Smith"),
                    new Claim(JwtClaimTypes.GivenName, "Alice"),
                    new Claim(JwtClaimTypes.FamilyName, "Smith"),
                    new Claim(JwtClaimTypes.Email, "AliceSmith@email.com"),
                    new Claim(JwtClaimTypes.EmailVerified, "true", ClaimValueTypes.Boolean),
                    new Claim(JwtClaimTypes.WebSite, "http://alice.com"),
                    new Claim(JwtClaimTypes.Address,
                        @"{ 'street_address': 'One Hacker Way', 'locality': 'Heidelberg', 'postal_code': 69118, 'country': 'Germany' }",
                        IdentityServerConstants.ClaimValueTypes.Json),
                    
                    // Die Rolle "ProUser" dient dazu, die Spielhistory abfragen zu dürfen.
                    new Claim(JwtClaimTypes.Role, "ProUser")
                }
            },
            // ...
    }
				
			

Jetzt sind alle Schritte im IdentityServer abgeschlossen und wir können uns der Web-API widmen. Hier ist nicht viel zu tun, wir müssen lediglich das Authorize-Attribute erweitern. Da es in unserer Beispielanwendung um das Spiel TicTacToe geht, gibt es für berechtigte Benutzer die Möglichkeit Ihre Spielhistorie abzurufen. Hierzu nutzen wir die Web-API GameHistory, welcher wir das Authorize-Attribute hinzufügen.

				
					[Route("[Controller]")]
// Hier wird zusätzlich noch die Rolle angegeben, die der Nutzer besitzen muss, um die Web-API aufrufen zu dürfen.
[Authorize(Roles = "ProUser")]
public class GamesHistoryController : Controller
//...
				
			

Wie im Code zu sehen ist, müssen wir nur die Property Roles des Authorize-Attributes setzen. Nachdem das Attribut nun gesetzt ist, können nur Nutzer die Historie abrufen, welche auch dazu berechtigt sind. Dies wird in der UI dadurch ersichtlich, dass neben dem Benutzernamen noch ein Icon erscheint, welches auf die Historie weiter leitet.

Im nächsten Schritt schauen wir uns an wie wir im Client über die Autorisierung Seiten oder bestimmte Teile einer Komponente für den Nutzer ein oder ausblenden können.

Berechtigung im Client prüfen

Folgende Beispielseite im Blazor-Client zeigt Informationen über den Benutzer an und gibt, sofern er eingeloggt ist, eine Liste der Claims aus.

				
					@page "/userInfo"

<AuthorizeView Roles="ProUser">
    <Authorized>
        <p>Hallo @context.User.Identity.Name, hier ist eine Liste deiner Nutzerrechte</p>
        
            @foreach (var claim in context.User.Claims)
            {
                <div class="mat-elevation-z8 sr-card">
                    <p>@claim.Type: </p>
                    <span>@claim.Value</span>
                </div>
            }
        
    </Authorized>
    <NotAuthorized>
        @if(context.User.Identity.IsAuthenticated) {
            <p>Nur berechtigte Nutzer können diesen Bereich sehen</p>
        } else {
            <RedirectToLogin />
        }
    </NotAuthorized>
</AuthorizeView>
				
			

Im Moment wird der Role-Claim jedoch nicht für Autorisierungszwecke verwendet. Dazu müssen wir eine Einstellung im AuthenticationStateProvider in der Program.cs treffen:

				
					builder.Services.AddOidcAuthentication(options =>
{
    builder.Configuration.Bind("Oidc",  options.ProviderOptions);
    
    // Hier teilen wir dem AuthenticationStateProvider mit, dass er den 'role'-Claim verwenden soll.
    // Dies dient dazu, dass wir diese auch später in unserer Komponente oder Seite nutzen und abfragen können.
    options.UserOptions.RoleClaim = "role";
});
				
			

Jetzt können wir die Rolle verwenden, um beispielsweise den Zugriff auf Seiten nur für berechtigte Nutzer zu autorisieren, zum Beispiel über das Authorize-Attribute:

				
					@page "/history"
@attribute [Authorize(Roles = "ProUser")]
				
			

Wir können auch Teile der UI auf der Grundlage der Rolle ein- und ausblenden:

				
					<AuthorizeView Roles="ProUser">
    <Authorized>
        <p>Nur berechtigte Nutzer können diesen Bereich sehen</p>
    </Authorized>
</AuthorizeView>
				
			

Natürlich kann es auch möglich sein, dass der Nutzer zwar authentifiziert aber nicht autorisiert ist:

				
					<AuthorizeRouteView Roles="ProUser">
    <NotAuthorized>
        @if (context.User.Identity.IsAuthenticated)
        {
            <p>Leider sind Sie nicht autorisiert.</p>
        }
        else
        {
            <RedirectToLogin />
        }
    </NotAuthorized>
</AuthorizeRouteView>
				
			

Fazit

Anhand einer Beispielanwendung konnten wir sehen, wie wir Authentifizierung und Autorisierung in eine Blazor-WebAssembly-App integrieren. Hierfür setzen wir den IdentityServer4 über das OpenID-Connect-Protokoll ein.

Wir haben ein Zugriffstoken angefordert und es dazu verwendet, eine geschützte Web-API aufzurufen und den Token im Header des HTTP-Aufrufs zu übergeben. Weiterhin haben wir gesehen, wie das Hinzufügen von Role-Claims sowohl in ID-Tokens als auch in Access-Tokens im IdentityServer funktioniert und wie diese dann für die Verwendung in Blazor verfügbar sind. Zum Schluss haben wir dann noch sichergestellt, dass auch die Web-API eine rollenbasierte Autorisierung implementiert.

Mehr Artikel zu Blazor, ASP.NET Core
Kostenloser
Newsletter

Aktuelle Artikel, Screencasts, Webinare und Interviews unserer Experten für Sie

Verpassen Sie keine Inhalte zu Angular, .NET Core, Blazor, Azure und Kubernetes und melden Sie sich zu unserem kostenlosen monatlichen Dev-Newsletter an.

Newsletter Anmeldung
Diese Artikel könnten Sie interessieren
Database Access with Sessions
.NET
kp_300x300

Data Access in .NET Native AOT with Sessions

.NET 8 brings Native AOT to ASP.NET Core, but many frameworks and libraries rely on unbound reflection internally and thus cannot support this scenario yet. This is true for ORMs, too: EF Core and Dapper will only bring full support for Native AOT in later releases. In this post, we will implement a database access layer with Sessions using the Humble Object pattern to get a similar developer experience. We will use Npgsql as a plain ADO.NET provider targeting PostgreSQL.
15.11.2023
Old computer with native code
.NET
kp_300x300

Native AOT with ASP.NET Core – Overview

Originally introduced in .NET 7, Native AOT can be used with ASP.NET Core in the upcoming .NET 8 release. In this post, we look at the benefits and drawbacks from a general perspective and perform measurements to quantify the improvements on different platforms.
02.11.2023
ASP.NET Core
favicon

Architektur-Modernisierung: Migration von WCF zu gRPC mit ASP.NET Core – ein pragmatischer Ansatz

Viele Projekte mit verteilten Anwendungen in der .NET-Welt basieren noch auf der Windows Communication Foundation (WCF). Doch wie kommt man weg von der "Altlast" und wie stellt man seinen Code auf sowohl moderne als auch zukunftssichere Beine? Eine mögliche Lösung ist gRPC.

13.04.2023
Blazor
favicon

gRPC Code-First mit ASP.NET Core 7 und Blazor WebAssembly

Wie in allen anderen browserbasierten Single-Page-Application (SPA) Frameworks, ist Blazor WebAssembly JSON-over-HTTP (über Web- oder REST-APIs) die bei weitem häufigste Methode, um Daten auszutauschen und serverseitige Vorgänge auszulösen. Der Client sendet eine HTTP-Anfrage mit JSON-Daten an eine URL, mitunter über unterschiedliche HTTP-Verben. Anschließend führt der Server eine Operation aus und antwortet mit einem HTTP-Statuscode und den resultierenden JSON-Daten. Warum sollte man das ändern? Nun, es gibt Gründe - vor allem wenn man in einem geschlossenen System ist und .NET sowohl im Frontend als auch im Backend einsetzt.
30.03.2023
Blazor
favicon

Blazor WebAssembly in .NET 7: UI-Performance-Optimierung auf Komponentenebene

Stockende UI, keine Reaktion nach dem Klick auf einen Button oder einer Eingabe in einem Feld - dies sind nur wenige Beispiele alltäglicher Probleme, die der Nutzung von Client-Anwendungen im Allgemeinen, und bei Webanwendungen im Speziellen, immer wieder auftreten können. In diesem Artikel schauen wir uns an, wie wir komponentenbasierte UIs in Blazor WebAssembly optimieren können, um dadurch eine für die Benutzer zufriedenstellende Geschwindigkeit und ein flüssiges UI zu bekommen.
29.03.2023
Blazor
sg

Understanding and Controlling the Blazor WebAssembly Startup Process

There are a lot of things going on in the background, when a Blazor WebAssembly application is being started. In some cases you might want to take a bit more control over that process. One example might be the wish to display a loading screen for applications that take some time for initial preparation, or when users are on a slow internet connection. However, in order to control something, we need to understand what is happening first. This article takes you down the rabbit hole of how a Blazor WASM application starts up.
07.03.2023