.NET 9 Blazor : Développement Full-Stack avec Blazor United en 2026

.NET 9 Blazor United réunit le rendu statique SSR, le mode Server et WebAssembly dans un framework full-stack unifié. Un tutoriel pratique couvrant les modes de rendu, le streaming, l'injection par constructeur et les patterns de production.

Développement full-stack .NET 9 Blazor United avec plusieurs modes de rendu

Blazor United dans .NET 9 fusionne trois stratégies de rendu — le rendu statique côté serveur (SSR), le mode interactif Server et WebAssembly — au sein d'un même framework full-stack cohérent. Ce modèle unifié, introduit avec .NET 8 et perfectionné dans .NET 9, supprime la nécessité de choisir entre différents modèles d'hébergement Blazor avant même d'écrire la première ligne de code.

Blazor United en résumé

Blazor United permet de combiner le rendu statique SSR, l'interactivité Server et l'interactivité WebAssembly au sein de la même application. Chaque composant déclare indépendamment son mode de rendu, offrant un contrôle précis sur les performances et l'interactivité page par page.

Mise en place d'une application Blazor Web avec .NET 9

Le template blazorweb de .NET 9 génère un projet préconfigué pour les trois modes de rendu. L'installation nécessite le SDK .NET 9 (version 9.0.100 ou ultérieure) et crée à la fois le projet serveur et le projet client (WASM) en une seule commande.

bash
# Créer une nouvelle Blazor Web App avec tous les modes de rendu activés
dotnet new blazorweb -n FullStackApp --interactivity Auto --all-interactive false
cd FullStackApp
dotnet run

Le flag --interactivity Auto active les modes de rendu Server et WebAssembly. Le paramètre --all-interactive false conserve le rendu statique SSR par défaut, de sorte que l'interactivité est activée composant par composant plutôt que globalement.

Comprendre les modes de rendu Blazor dans .NET 9

Chaque composant d'une Blazor Web App adopte un mode de rendu qui détermine où il s'exécute, s'il supporte l'interactivité et comment il communique avec le serveur. .NET 9 propose quatre modes distincts.

| Mode de rendu | Hébergement | Interactivité | Cas d'usage | |---|---|---|---| | SSR statique | Serveur | Aucune | Pages marketing, documentation, contenu SEO | | Interactive Server | Serveur via SignalR | Complète | Tableaux de bord, CRUD, formulaires | | Interactive WebAssembly | Navigateur via WASM | Complète | Mode hors ligne, logique client intensive | | Interactive Auto | Serveur puis WASM | Complète | Le meilleur des deux — chargement rapide + autonomie |

Le mode de rendu est défini au niveau du composant avec la directive @rendermode. Cette granularité par composant signifie qu'une seule page peut mélanger des sections statiques et interactives.

Components/Pages/Dashboard.razorcsharp
@page "/dashboard"
@rendermode InteractiveServer

<PageTitle>Dashboard</PageTitle>

<h1>Real-Time Metrics</h1>

<!-- This component renders interactively via SignalR -->
<MetricsChart />

<!-- Static content below renders as plain HTML -->
<footer>Updated every 5 seconds</footer>

Une nouveauté de l'API .NET 9 — ComponentBase.RendererInfo — permet aux composants de détecter leur mode de rendu actuel à l'exécution, rendant possible une logique conditionnelle basée sur le contexte d'exécution.

Components/Shared/AdaptiveComponent.razorcsharp
@if (RendererInfo.IsInteractive)
{
    <button @onclick="HandleClick">Interactive Action</button>
}
else
{
    <a href="/fallback">Static Fallback Link</a>
}

@code {
    private void HandleClick()
    {
        // Runs only in interactive modes (Server or WASM)
    }
}

Le rendu en streaming pour les pages à forte charge asynchrone

Les pages SSR statiques qui récupèrent des données de manière asynchrone peuvent bloquer la réponse jusqu'à la fin de toutes les tâches. Le rendu en streaming résout ce problème en envoyant immédiatement du HTML de substitution, puis en transmettant le contenu définitif à mesure que les données arrivent. Dans .NET 9, l'attribut [StreamRendering] ne nécessite plus le paramètre true — il est activé par défaut.

Components/Pages/Products.razorcsharp
@page "/products"
@attribute [StreamRendering]

<PageTitle>Product Catalog</PageTitle>

@if (products is null)
{
    <p>Loading products...</p>
}
else
{
    <div class="product-grid">
        @foreach (var product in products)
        {
            <ProductCard Item="@product" />
        }
    </div>
}

@code {
    private List<Product>? products;

    // Data loads asynchronously; streaming pushes updates to the browser
    protected override async Task OnInitializedAsync()
    {
        products = await ProductService.GetAllAsync();
    }
}

Le rendu en streaming repose sur le transfert par morceaux HTTP/1.1 (chunked transfer encoding), pris en charge par tous les navigateurs modernes. Le contenu de substitution s'affiche instantanément, et le balisage final le remplace sans rechargement complet de la page.

Injection par constructeur dans les composants Blazor

.NET 9 introduit l'injection par constructeur pour les composants Blazor, complétant la directive @inject et l'attribut [Inject] existants. Combinée aux constructeurs primaires de C# 12, les dépendances de services deviennent partie intégrante de la signature du composant.

Components/Pages/OrderHistory.razorcsharp
@page "/orders"
@rendermode InteractiveServer

<h2>Order History</h2>

@if (orders is not null)
{
    <table>
        <thead>
            <tr><th>Order ID</th><th>Date</th><th>Total</th></tr>
        </thead>
        <tbody>
            @foreach (var order in orders)
            {
                <tr>
                    <td>@order.Id</td>
                    <td>@order.PlacedAt.ToShortDateString()</td>
                    <td>@order.Total.ToString("C")</td>
                </tr>
            }
        </tbody>
    </table>
}

@code {
    // Constructor injection via primary constructor
    [Inject] public required IOrderService OrderService { get; set; }
    [Inject] public required NavigationManager Nav { get; set; }

    private List<Order>? orders;

    protected override async Task OnInitializedAsync()
    {
        orders = await OrderService.GetRecentOrdersAsync();
    }
}

L'injection par constructeur rend les dépendances explicites et simplifie les tests unitaires. Les services enregistrés dans Program.cs sont résolus automatiquement, y compris les services à clé ajoutés via builder.Services.AddKeyedScoped<T>().

Prêt à réussir tes entretiens .NET ?

Entraîne-toi avec nos simulateurs interactifs, fiches express et tests techniques.

Le mode Interactive Auto — le meilleur des deux mondes

Le mode Auto offre le temps de chargement perçu le plus rapide. Lors de la première visite, le composant s'exécute sur le serveur via SignalR pendant que le runtime WebAssembly se télécharge en arrière-plan. Lors des visites suivantes, l'exécution bascule entièrement vers le navigateur.

Components/Pages/Chat.razorcsharp
@page "/chat"
@rendermode InteractiveAuto

<h2>Live Chat</h2>

<div class="chat-messages">
    @foreach (var msg in messages)
    {
        <div class="message">@msg.Author: @msg.Text</div>
    }
</div>

<input @bind="newMessage" @onkeydown="HandleKey" placeholder="Type a message..." />

@code {
    [Inject] public required IChatService ChatService { get; set; }

    private List<ChatMessage> messages = new();
    private string newMessage = string.Empty;

    protected override async Task OnInitializedAsync()
    {
        messages = await ChatService.GetRecentMessagesAsync();
    }

    private async Task HandleKey(KeyboardEventArgs e)
    {
        if (e.Key == "Enter" && !string.IsNullOrWhiteSpace(newMessage))
        {
            await ChatService.SendAsync(newMessage);
            newMessage = string.Empty;
        }
    }
}

Le mode Auto exige que les dépendances et la logique du composant fonctionnent dans les deux contextes, serveur et WASM. Les services doivent être abstraits derrière des interfaces et enregistrés dans les conteneurs d'injection de dépendances du serveur et du client.

Reconnexion et résilience dans .NET 9

.NET 9 réécrit la logique de reconnexion de Blazor Server avec une stratégie de backoff exponentiel. Au lieu de réessayer à intervalles fixes, le framework commence par des tentatives rapides puis augmente progressivement le délai — réduisant la charge serveur lors des pannes tout en récupérant rapidement après de brèves interruptions.

Améliorations clés :

  • Revenir sur un onglet déclenche une tentative de reconnexion immédiate
  • Si le serveur a déjà libéré le circuit, la page se rafraîchit automatiquement
  • L'interface par défaut affiche « Reconnexion au serveur... » avec un indicateur de progression
  • Les intervalles de nouvelle tentative sont configurables via Blazor.start()
wwwroot/app.js — Custom reconnection configurationjavascript
Blazor.start({
    circuit: {
        reconnectionOptions: {
            retryIntervalMilliseconds: (retryNumber) => {
                // Exponential backoff: 200ms, 400ms, 800ms, max 30s
                return Math.min(200 * Math.pow(2, retryNumber), 30000);
            },
            maxRetries: 15
        }
    }
});

SSR statique avec interactivité sélective

L'architecture recommandée pour la plupart des Blazor Web Apps en 2026 commence par le SSR statique par défaut, en ajoutant l'interactivité uniquement là où c'est nécessaire. L'attribut [ExcludeFromInteractiveRouting] (nouveauté .NET 9) marque les pages qui doivent rester statiques — utile pour les pages qui dépendent de cookies HTTP ou du cycle requête/réponse.

Components/Pages/Privacy.razorcsharp
@page "/privacy"
@attribute [ExcludeFromInteractiveRouting]

<PageTitle>Privacy Policy</PageTitle>

<!-- This page always renders as static HTML -->
<!-- Even if global interactivity is enabled -->
<article>
    <h1>Privacy Policy</h1>
    <p>Last updated: April 2026</p>
    <!-- Content -->
</article>

Ce pattern fonctionne bien avec MapStaticAssets, un nouveau middleware .NET 9 qui compresse et « fingerprinte » les fichiers statiques au moment du build, remplaçant l'ancienne approche UseStaticFiles par une livraison optimisée prête à l'emploi.

Gains de performances avec la compilation AOT de .NET 9

.NET 9 AOT (Ahead-of-Time) réduit la taille des payloads WebAssembly jusqu'à 40 % par rapport à .NET 8. Le démarrage de Blazor WASM est 25 % plus rapide selon les benchmarks Google Lighthouse. Ces gains s'appliquent automatiquement lors de la publication avec AOT activé.

bash
# Publish with AOT for production
dotnet publish -c Release -p:RunAOTCompilation=true

La compression WebSocket est également activée par défaut pour les composants interactifs Server. Une Content Security Policy (frame-ancestors: 'self') est appliquée automatiquement pour atténuer les vecteurs d'attaque liés à la compression.

Passe à la pratique !

Teste tes connaissances avec nos simulateurs d'entretien et tests techniques.

Conclusion

  • Blazor United dans .NET 9 élimine le choix du modèle d'hébergement en combinant SSR statique, Server et WebAssembly dans un seul projet
  • Les modes de rendu se définissent par composant avec @rendermode pour optimiser chaque page indépendamment — statique pour le SEO, Server pour les tableaux de bord, Auto pour les scénarios hybrides
  • Le rendu en streaming avec [StreamRendering] supprime les délais de chargement sur les pages à forte charge asynchrone
  • L'injection par constructeur (nouveauté .NET 9) rend les dépendances des composants explicites et testables
  • Le mode Auto offre un premier affichage rapide via Server, puis bascule sur WASM pour une indépendance totale côté client
  • Le backoff exponentiel pour la reconnexion réduit les connexions perdues et élimine les rafraîchissements manuels
  • La compilation AOT réduit la taille des payloads WASM de 40 % et le temps de démarrage de 25 %
  • Toute Blazor Web App devrait démarrer avec le SSR statique par défaut, puis ajouter l'interactivité là où l'expérience utilisateur l'exige

Passe à la pratique !

Teste tes connaissances avec nos simulateurs d'entretien et tests techniques.

Tags

#dotnet
#blazor
#aspnet-core
#webassembly
#full-stack

Partager

Articles similaires