.NET8 et Blazor United : L'avenir du Web ?
Depuis la sortie de .NET Core, Microsoft cherche à s'améliorer dans le domaine de l'Open Source et du CrossPlatform . Le mois dernier est sortie la version 8.0 (LTS ) de .NET. Une nouvelle version sort chaque année. Les versions de .NET alternent entre LTS et STS. .NET 8 comporte un énorme virage notamment à propos de Blazor. Dans cet article, nous vous montrons ce qu'est Blazor.
Blazor, kesako ?
Blazor est un framework avec une approche par composant (écrit en Razor ) proposé par Microsoft, qui a maintenant plusieurs années. Il fait partie d'ASP .NET Core. Avant .NET8, un projet Blazor n'avait qu'un unique mode de fonctionnement : Blazor Server ou Blazor WebAssembly. En effet, ayant un mode de fonctionnement bien différent, ces deux versions n'étaient pas compatibles au sein d'un même projet.
Blazor United
.NET 8 annonce la sortie de Blazor United. Il s'agit d'une version de Blazor qui sera capable de rendre des composants Razor de différentes manières au sein d'un même projet. Il permet donc au développeur de s'adapter au besoin de chaque page afin d'améliorer les performances de rendu et d'interactivité de son application.
Quatre modes de rendu peuvent être choisis pour un composant :
- Static SSR (Server Side Rendering) : Rendu serveur non dynamique
- Interactive WebServer : Rendu serveur dynamique
- Interactive WebAssembly : Rendu client dynamique
- Interactive Auto : Rendu serveur dynamique lors du premier chargement de la page, puis rendu client dynamique
Les exemples que nous allons montrer par la suite ont été réalisés à l'aide d'un projet créé à partir du modèle Blazor Web App de Visual Studio 2022.
Mode Static SSR
Le mode de rendu Static SSR (mode de rendu utilisé par défaut par les composants) se rapproche des Razors Pages ou bien du MVC pour les plus anciens d'entre nous, c'est-à-dire que le contenu HTML est généré côté serveur et est renvoyé au client. Si des interactions doivent être générées, elles devront l'être à l'aide de Javascript.
Lorsque nous lançons l'application, nous arrivons sur la page d'accueil qui est rendue statiquement. Vous trouverez ci-contre les requêtes générées par l'application.
Nous récupérons ici uniquement des contenus statiques renvoyés par le serveur (javascript, css, image ...) et un document HTML généré.
Streaming Rendering
Le chargement de données avec une source de données externe (API, base de données, etc.) ou toute autre opération asynchrone nécessaire à la page peut prendre du temps. Par défaut, lorsque l'utilisateur tente d'accéder à la page, il doit attendre la récupération des données pour avoir un premier affichage. Sans Blazor, la solution est d'utiliser des appels asynchrones (AJAX) à partir du navigateur client.
Blazor, quant à lui, propose le Streaming Rendering qui permet d'obtenir un premier rendu de la page complète beaucoup plus rapidement en remplaçant les données chargées par un placeholder (un loader par exemple). Une fois le traitement asynchrone terminé, le nouveau contenu HTML est envoyé au sein de la même réponse HTTP. Le contenu HTML est mis à jour partiellement ("patch") c'est-à-dire que seul le contenu modifié est mis à jour.
Dans l'exemple ci-contre, nous utilisons le composant Weather fourni par défaut par le projet. Le chargement des données est simulé à 10 secondes.
Lorsque l'on requête la page /weather à l'aide de la commande CURL, nous avons un résultat en deux parties.
La première partie renvoie le HTML de la page sans les données chargées (et donc le placeholder de chargement) ainsi que des commentaires générés Blazor qui vont servir à la modification du DOM par la suite.
Dans la seconde partie de réponse, nous recevons seulement une partie du HTML, elle aussi contenant des commentaires générés par Blazor. A l'aide de ces commentaires, il est capable de mettre à jour le DOM précédemment construit.
Il est à noter que si la réponse est en plusieurs parties, le serveur répond au sein d'une seule et unique requête HTTP, ce qui est facilement observable en ligne de commande à l'aide de CURL. De plus, il peut y avoir plus de 2 réponses et PATCH dans le DOM (par exemple, si on joue avec un compteur ou plusieurs chargements de données).
Avantages
- Le Streaming Rendering permet un premier chargement rapide si il y a des chargements de données
- Le pure Static SSR permet de renvoyer des "simples" pages HTML
Inconvénients
- Moins fluide que les SPA / Blazor Server
Interactive WebServer
Ce mode de rendu correspond à celui de Blazor Server, disponible avant la sortie de Blazor United. Il est basé sur le système de WebSocket de SignalR. Lorsqu'un utilisateur accède à une page utilisant ce mode de rendu, une WebSocket est ouverte. Les composants Blazor sont exécutés côté serveur, et ses interactions sont gérées par le biais de cette WebSocket.
Afin de voir comment se passe le chargement d'une page avec BlazorServer, nous allons utiliser la page Counter. Cette page propose un simple bouton qui incrémente un compteur :
Pour le bien de cet exemple, nous avons rendu le composant Counter.razor à l'aide de BlazorServer en le déplaçant dans le projet dédié au serveur de l'application .NET.
Lorsque nous interrogeons la page /counter, nous voyons qu'une WebSocket a été ouverte dans la console du navigateur afin de gérer les interactions :
Cette requête se ferme dès que l'on change de page, et s'ouvre à nouveau lorsque l'on revient dessus.
Avantages
- Application légère à utiliser
- Le navigateur n'est pas obligé de supporter les WebAssembly
Le code du composant n'est pas envoyé au client
- Possibilité de gérer des appels externes (bases de données, API, ...) sans créer d'API
Inconvénients
- Si l'application a beaucoup d'utilisateurs, alors beaucoup de WebSockets sont ouvertes, ce qui peut rapidement provoquer un souci de surcharge serveur et donc de latence
- Mode déconnecté non possible
Interactive WebAssembly
Blazor WebAssembly est quand à lui basé sur les WebAssembly (WASM). C'est une SPA à l'instar de React, Vue.js, ... Les WASM sont un standard du W3C. Elles permettent d'exécuter du code dans notre navigateur. Dans notre cas, il s'agit du code de notre application Blazor écrites en C#. Cela signifie que notre client embarque nos sources (compilées) ainsi que le Runtime .NET. Grâce à ces WebAssembly, notre application est capable de s'exécuter et gérer ses interactions dans le navigateur, sans WebSocket.
Pour cet exemple, nous allons travailler avec le composant Counter qui était initialement présent au sein du projet créé. Avant que nous le déplacions pour l'exemple de Blazor Server, ce composant était présent dans un projet "Client". Notre application est découpée en deux parties, une qui sera le serveur .NET, et l'autre (Client) qui sera compilée en WASM. Le code sera donc "accessible" par tout le monde. Pour que les composants du projet Client fonctionnent, il faut ajouter le paramétrage suivant au sein du Program.cs du projet principal.
La position du composant dans le projet client et son paramétrage (@rendermode InteractiveWebAssembly), vont faire qu'il sera rendu à l'aide des WASM.
Dès que l'on navigue sur la page /counter, nous voyons dans la console réseau les WASM téléchargées.
La première correspond au runtime .NET. Les autres sont celles nécessaires pour faire fonctionner le projet, on y retrouve notamment les nuget. Ces WASM sont mises en cache, et lorsque la page est rechargée, il n'y a donc pas de nouvelle requête pour les télécharger.
Avantages
- Application fonctionnelle sans connexion internet si les composants, les dépendances ainsi que le .NET Runtime ont été téléchargés (sauf pour les appels externes : API)
- Mode déconnecté possible
- Faible charge serveur
Inconvénients
- Fonctionnalités pouvant être limitées par le navigateur
- Certains navigateurs peuvent ne pas supporter les WASM. Ce n'est pas le cas des principaux navigateurs
- Taille de téléchargement de l'application volumineux
- Le code est accessible par le client
- Nécessite une API pour récupérer des données
Interactive Auto
Le but de ce mode de rendu est de garder le meilleur de Blazor Server et Blazor WebAssembly. Lors du premier chargement d'une page en rendu automatique, une web socket est ouverte. La page se comporte alors comme dans Blazor Server. Pendant ce temps, les WASM de BlazorWebAssembly sont téléchargées. Lorsque l'on revient sur la page, celle-ci va maintenant fonctionner à l'aide des WASM et non plus des web sockets.
Notre composant Counter (toujours placé dans le dossier client car sinon les WASM ne seront pas générées) passe en mode automatique (à l'aide de @rendermode InteractiveAuto) :
Lors du premier chargement de la page Counter, nous pouvons observer le téléchargement des WASM et l'ouverture d'une WebSocket.
Le premier encadré rouge correspond à la WebSocket, le second aux WASM.
Lorsque l'on quitte puis revient sur la page, il n'y a plus ces chargements. La page va fonctionner avec les WASM mis en cache préalablement.
Il faudra donc penser pendant le développement le composant sera rendu avec les deux modes (Server et WASM). Cela impacte le développement, notamment au niveau du chargement des données, il faudra une source externe de données telle qu'une API par exemple.
Avantages
- Chargement rapide car utilisation de WebSocket
- Les avantages de BlazorServer lors du premier chargement
- Les avantages de BlazorWebAssembly à partir du second chargement
Inconvénients
- Les inconvénients de BlazorServer lors du premier chargement
- Les inconvénients de BlazorWebAssembly lors du second chargement
Ce qu'il faut retenir !
Blazor United a pour but de répondre de la meilleure des manières aux besoins clients. Sa force réside dans sa flexibilité au niveau des rendus, sans pour autant perdre en performance. Il est possible de rendre du contenu statique côté serveur, des pages interactives, etc.
Il est aussi un atout pour les développeurs puisque malgré tous ses modes de rendu, une seule syntaxe est utilisée : Razor. Si vous n'êtes pas un mordu de Javascript, vous n'en avez que très peu voire pas besoin ; la majorité du code sera du C# et du HTML.
L'équipe FTEL