Application web progressive (PWA) Blazor sur ASP.NET Core

Remarque

Ceci n’est pas la dernière version de cet article. Pour la version actuelle, consultez la version .NET 8 de cet article.

Important

Ces informations portent sur la préversion du produit, qui est susceptible d’être en grande partie modifié avant sa commercialisation. Microsoft n’offre aucune garantie, expresse ou implicite, concernant les informations fournies ici.

Pour la version actuelle, consultez la version .NET 8 de cet article.

Une application web progressive (PWA) Blazor est une application monopage (SPA) qui utilise des API et des fonctionnalités de navigateurs modernes pour se comporter comme une application de bureau.

Blazor WebAssembly est une plateforme standardisée d’applications web côté client, qui peut utiliser toutes les API de navigateur existantes, y compris les API PWA requises pour les fonctionnalités suivantes :

  • Exécution hors connexion et chargement instantané, indépendamment de la vitesse du réseau.
  • Exécution dans la propre fenêtre de l’application, et pas seulement dans une fenêtre de navigateur.
  • Lancement à partir du menu Démarrer, du dock ou de l’écran d’accueil du système d’exploitation de l’hôte.
  • Réception des notifications Push d’un serveur back-end, même quand l’utilisateur n’interagit pas avec l’application.
  • Mises à jour automatiques en arrière-plan.

Le terme progressive employé pour décrire ce type d’applications s’explique ainsi :

  • Un utilisateur découvre et utilise d’abord l’application dans son navigateur web comme n’importe quelle autre application SPA.
  • Ensuite, progressivement, l’utilisateur installe l’application dans son système d’exploitation et active les notifications Push.

Créer un projet à partir du modèle PWA

Quand vous créez une application Blazor WebAssembly, cochez la case Application web progressive.

Vous pouvez éventuellement configurer PWA pour une application créée à partir du modèle de projet Blazor WebAssemblyhébergé sur ASP.NET Core. Le scénario PWA est indépendant du modèle d’hébergement.

Convertir une application Blazor WebAssembly existante en PWA

Convertissez une application Blazor WebAssembly existante en application PWA en suivant les instructions de cette section.

Dans le fichier projet de l’application :

  • Ajoutez la propriété ServiceWorkerAssetsManifest suivante à un PropertyGroup :

      ...
      <ServiceWorkerAssetsManifest>service-worker-assets.js</ServiceWorkerAssetsManifest>
    </PropertyGroup>
    
  • Ajoutez l’élément ServiceWorker suivant à un ItemGroup :

    <ItemGroup>
      <ServiceWorker Include="wwwroot\service-worker.js" 
        PublishedContent="wwwroot\service-worker.published.js" />
    </ItemGroup>
    

Pour obtenir des ressources statiques, utilisez l’une des approches suivantes :

  • Créez un projet PWA distinct en exécutant la commande dotnet new dans un interpréteur de commandes :

    dotnet new blazorwasm -o MyBlazorPwa --pwa
    

    Dans la commande précédente, l’option -o|--output crée un dossier pour l’application nommée MyBlazorPwa.

    Si vous ne convertissez pas l’application vers la dernière version, ignorez l’option -f|--framework. L’exemple suivant crée l’application pour ASP.NET Core version 5.0 :

    dotnet new blazorwasm -o MyBlazorPwa --pwa -f net5.0
    
  • Accédez au dépôt GitHub ASP.NET Core à l’URL suivante, qui fournit des liens vers la source et les ressources de référence de la branche main. Sélectionnez la version que vous utilisez dans la liste déroulante Switch branches or tags (Changer de branches ou d’étiquettes) qui s’applique à votre application.

    Dossier wwwroot du modèle de projet Blazor WebAssembly (branche main du dépôt GitHub dotnet/aspnetcore)

    Remarque

    Les liens de documentation vers la source de référence .NET chargent généralement la branche par défaut du référentiel, qui représente le développement actuel pour la prochaine version de .NET. Pour sélectionner une balise pour une version spécifique, utilisez la liste déroulante Échanger les branches ou les balises. Pour plus d’informations, consultez Comment sélectionner une balise de version du code source ASP.NET Core (dotnet/AspNetCore.Docs #26205).

    À partir du dossier wwwroot source soit de l’application que vous avez créée, soit des ressources de référence dans le dépôt GitHub dotnet/aspnetcore, copiez les fichiers suivants vers le dossier wwwroot de l’application :

    • icon-192.png
    • icon-512.png
    • manifest.webmanifest
    • service-worker.js
    • service-worker.published.js

Dans le fichier wwwroot/index.html de l’application :

  • Ajoutez les éléments <link> pour le manifeste et l’icône d’application :

    <link href="manifest.webmanifest" rel="manifest" />
    <link rel="apple-touch-icon" sizes="512x512" href="icon-512.png" />
    <link rel="apple-touch-icon" sizes="192x192" href="icon-192.png" />
    
  • Accédez au référentiel GitHub ASP.NET Core à l’adresse URL suivante qui fournit des liens vers la source et les ressources de référence de la branche release/7.0. Si vous utilisez une version d’ASP.NET Core ultérieure à la version 7.0, modifiez le sélecteur de version de document pour afficher les instructions mises à jour pour cette section. Sélectionnez la version que vous utilisez dans la liste déroulante Switch branches or tags (Changer de branches ou d’étiquettes) qui s’applique à votre application.

    Dossier wwwroot du modèle de projet Blazor WebAssembly (branche release/7.0 du dépôt GitHub dotnet/aspnetcore)

    Remarque

    Les liens de documentation vers la source de référence .NET chargent généralement la branche par défaut du référentiel, qui représente le développement actuel pour la prochaine version de .NET. Pour sélectionner une balise pour une version spécifique, utilisez la liste déroulante Échanger les branches ou les balises. Pour plus d’informations, consultez Comment sélectionner une balise de version du code source ASP.NET Core (dotnet/AspNetCore.Docs #26205).

    À partir du dossier wwwroot source soit de l’application que vous avez créée, soit des ressources de référence dans le dépôt GitHub dotnet/aspnetcore, copiez les fichiers suivants vers le dossier wwwroot de l’application :

    • favicon.png
    • icon-512.png
    • manifest.json
    • service-worker.js
    • service-worker.published.js

Dans le fichier wwwroot/index.html de l’application :

  • Ajoutez les éléments <link> pour le manifeste et l’icône d’application :

    <link href="manifest.json" rel="manifest" />
    <link rel="apple-touch-icon" sizes="512x512" href="icon-512.png" />
    
  • Ajoutez la balise <script> suivante dans la balise </body> fermante immédiatement après la balise de script blazor.webassembly.js :

        ...
        <script>navigator.serviceWorker.register('service-worker.js');</script>
    </body>
    

Installation et manifeste de l’application

Quand ils découvrent une application basée sur le modèle PWA, les utilisateurs ont l’option d’installer l’application dans le menu Démarrer, le dock ou l’écran d’accueil de leur système d’exploitation. Cette option leur est présentée différemment selon le navigateur qu’ils utilisent. Dans les navigateurs de bureau basés sur Chromium, comme Edge ou Chrome, il y a un bouton Ajouter dans la barre d’URL. Quand les utilisateurs sélectionnent le bouton Ajouter, une boîte de dialogue de confirmation s’affiche :

La boîte de dialogue de confirmation dans Google Chrome présente à l’utilisateur un bouton Installer pour l’application « MyBlazorPwa ».

Sur iOS, les utilisateurs peuvent installer l’application PWA en utilisant le bouton Partager de Safari et son option Ajouter à l’écran Home. Sur Chrome pour Android, les utilisateurs doivent sélectionner le bouton Menu dans le coin supérieur droit, puis sélectionner Ajouter à l’écran Home.

Une fois installée, l’application s’ouvre dans sa propre fenêtre sans barre d’adresse :

L’application « MyBlazorPwa » s’exécute dans une fenêtre Google Chrome sans barre d’adresse.

Pour personnaliser le titre, le jeu de couleurs, l’icône ou d’autres détails de la fenêtre, consultez le fichier manifest.json dans le répertoire wwwroot du projet. Le schéma de ce fichier est défini par les standards du Web. Pour plus d’informations, consultez Documentation web MDN : Manifeste des applications web.

Prise en charge hors connexion

Par défaut, les applications créées avec l’option de modèle PWA peuvent s’exécuter hors connexion. Un utilisateur doit d’abord découvrir l’application quand il est connecté. Le navigateur télécharge et met en cache automatiquement toutes les ressources nécessaires à l’exécution hors connexion de l’application.

Important

La prise en charge du développement interférerait avec le cycle de développement habituel consistant à apporter des modifications et à les tester. C’est pourquoi la prise en charge du mode hors connexion est possible uniquement pour les applications publiées.

Warning

Si vous envisagez de distribuer une application PWA exécutable hors connexion, plusieurs avertissements et mises en garde importants sont à prendre en compte. Ces scénarios sont inhérents à toutes les applications PWA exécutables hors connexion ; ils ne sont pas propres à Blazor. Veillez à lire et à bien comprendre ces mises en garde avant de faire des hypothèses sur le fonctionnement de votre application exécutable hors connexion.

Pour voir comment fonctionne la prise en charge du mode hors connexion :

  1. Publiez l’application. Pour plus d’informations, consultez Héberger et déployer ASP.NET Core Blazor.

  2. Déployez l’application sur un serveur prenant en charge HTTPS et accédez à l’application dans un navigateur à son adresse HTTPS sécurisée.

  3. Ouvrez les outils de développement du navigateur et vérifiez qu’un service worker est inscrit pour l’hôte sous l’onglet Application :

    L’onglet « Application » des Outils de développement de Google Chrome affiche un Service Worker activé et en cours d’exécution.

  4. Rechargez la page et examinez l’onglet Réseau. Service Worker ou le cache mémoire est répertorié comme sources pour toutes les ressources de la page :

    Onglet « Réseau » des Outils de développement de Google Chrome montrant les sources pour toutes les ressources de la page.

  5. Pour vérifier que le navigateur ne dépend pas de l’accès réseau pour charger l’application, utilisez l’une de ces deux méthodes :

    • Arrêtez le serveur web et regardez si l’application continue de fonctionner normalement, y compris les rechargements de page. De même, regardez si l’application continue de fonctionner normalement en cas de connexion réseau lente.
    • Demandez au navigateur de simuler le mode hors connexion sous l’onglet Réseau :

    Onglet « Réseau » des Outils de développement de Google Chrome, avec l’option de liste déroulante du mode navigateur qui est passée de « En ligne » à « Hors connexion ».

La prise en charge du mode hors connexion avec un service worker est un standard du Web ; elle n’est pas propre à Blazor. Pour plus d’informations sur les service workers, consultez Documentation web MDN : API de service worker. Pour en savoir plus sur les schémas d’utilisation courants des service workers, consultez Google Web : Le cycle de vie d’un service worker.

Le modèle PWA de Blazor produit deux fichiers de service worker :

  • wwwroot/service-worker.js, qui est utilisé pendant le développement.
  • wwwroot/service-worker.published.js, qui est utilisé après la publication de l’application.

Pour partager la logique entre les deux fichiers de service worker, envisagez l’approche suivante :

  • Ajoutez un troisième fichier JavaScript, qui contient la logique commune.
  • Utilisez self.importScripts pour charger la logique commune dans les deux fichiers de service worker.

Stratégie de récupération cache-first

Le service worker service-worker.published.js intégré résout les requêtes en suivant une stratégie cache-first (cache en priorité). Cela signifie que le service worker retourne en priorité le contenu mis en cache, sans prendre en compte si l’utilisateur dispose d’un accès réseau ou si du contenu plus récent est disponible sur le serveur.

La stratégie cache-first offre plusieurs avantages :

  • Elle garantit la fiabilité. L’accès réseau n’est pas un état booléen. Un utilisateur n’est pas simplement en ligne (connecté) ou hors connexion :

    • L’appareil de l’utilisateur peut supposer qu’il est en ligne, mais le réseau peut être si lent qu’il est impossible d’attendre.
    • Le réseau peut retourner des résultats non valides pour certaines URL, par exemple quand un portail WIFI captif bloque ou redirige des requêtes.

    C’est pourquoi l’API navigator.onLine du navigateur n’est pas fiable et ne doit pas avoir de dépendances.

  • Elle garantit l’exactitude. Quand il crée un cache de ressources hors connexion, le service worker utilise le hachage de contenu pour être sûr de récupérer (fetch) un instantané complet et intrinsèquement cohérent des ressources à un instant t. Ce cache est ensuite utilisé comme unité atomique. Il est inutile de demander au réseau des ressources plus récentes, car les seules versions requises sont celles qui se trouvent déjà dans le cache. Toute autre ressource risquerait d’introduire des problèmes d’incohérence et d’incompatibilité (par exemple, en essayant d’utiliser des versions d’assemblys .NET qui n’ont pas été compilés ensemble).

Si vous devez empêcher le navigateur de récupérer service-worker-assets.js à partir de son cache HTTP, par exemple pour résoudre les échecs temporaires de vérification de l’intégrité au déploiement d’une nouvelle version du service worker, mettez à jour l’inscription du service worker dans wwwroot/index.html en définissant updateViaCache sur « none » :

<script>
  navigator.serviceWorker.register('/service-worker.js', {updateViaCache: 'none'});
</script>

Mises à jour en arrière-plan

Vous pouvez vous représenter mentalement une application PWA exécutable d’abord hors connexion comme une application qui se comporte comme une application mobile qui peut être installée. L’application démarre immédiatement, quelle que soit la connectivité réseau, mais la logique de l’application installée provient d’un instantané d’un point dans le temps qui ne correspond pas forcément à la dernière version.

Le modèle PWA de Blazor produit des applications qui tentent automatiquement de se mettre à jour en arrière-plan chaque fois que l’utilisateur découvre une application et dispose d’une connexion réseau opérationnelle. Voici le processus :

  • Au moment de la compilation, le projet génère un manifeste de ressources pour le service worker. Par défaut, le manifeste s’appelle service-worker-assets.js. Le manifeste liste toutes les ressources statiques dont l’application a besoin pour s’exécuter hors connexion, telles que les assemblys .NET, les fichiers JavaScript et les fichiers CSS, y compris leurs hachages de contenu. La liste des ressources est chargée par le service worker afin qu’il sache quelles ressources mettre en cache.
  • Chaque fois que l’utilisateur découvre l’application, le navigateur redemande service-worker.js et service-worker-assets.js en arrière-plan. Les fichiers sont comparés octet par octet avec le service worker installé existant. Si le serveur retourne le contenu modifié pour l’un de ces fichiers, le service worker tente d’installer une nouvelle version de lui-même.
  • Lors de l’installation de sa nouvelle version, le service worker crée un autre cache distinct pour les ressources hors connexion, puis commence à remplir ce cache avec les ressources listées dans service-worker-assets.js. Cette logique est implémentée dans la fonction onInstall à l’intérieur de service-worker.published.js.
  • Le processus aboutit quand toutes les ressources sont chargées sans erreur et que tous les hachages de contenu correspondent. En cas de réussite, le nouveau service worker entre dans un état d’attente d’activation. Dès que l’utilisateur ferme l’application (tous les onglets et fenêtres d’application doivent être fermés), le nouveau service worker devient actif et est utilisé pour les découvertes suivantes de l’application. L’ancien service worker et son cache sont supprimés.
  • Si le processus n’aboutit pas, l’instance du nouveau service worker est supprimée. Le processus de mise à jour sera retenté à la prochaine visite de l’utilisateur, quand le client aura, espérons-le, une meilleure connexion réseau pour traiter correctement les requêtes.

Personnalisez ce processus en modifiant la logique du service worker. Aucun des comportements précédents n’est propre à Blazor. Il s’agit simplement de l’expérience par défaut fournie par l’option de modèle PWA. Pour plus d’informations, consultez Documents web MDN : API de service worker.

Résolution des requêtes

Comme nous l’avons expliqué dans la section Stratégie de récupération cache-first, le service worker par défaut utilise une stratégie cache-first, c’est-à-dire qu’il essaie de retourner en priorité le contenu mis en cache quand il est disponible. S’il n’y a pas de contenu mis en cache pour une URL donnée, par exemple lors de la récupération de données depuis une API back-end, le service worker utilise une requête réseau standard. La requête réseau réussit si le serveur est accessible. Cette logique est implémentée dans la fonction onFetch à l’intérieur de service-worker.published.js.

Si les composants Razor de l’application dépendent de la récupération de données à partir d’API back-end et que vous souhaitez fournir une expérience utilisateur conviviale pour les requêtes ayant échoué en raison de l’indisponibilité du réseau, implémentez la logique dans les composants de l’application. Par exemple, utilisez try/catch autour des requêtes HttpClient.

Prise en charge des pages rendues par le serveur

Réfléchissez à ce qui se passe lorsque l’utilisateur accède pour la première fois à une URL comme /counter ou à tout autre lien profond dans l’application. Dans de tels cas, au lieu de retourner le contenu mis en cache en tant que /counter, vous voulez que le navigateur charge le contenu mis en cache en tant que /index.html pour démarrer votre application Blazor WebAssembly. Ces requêtes initiales sont appelées requêtes de navigation, par opposition aux :

  • requêtes subresource pour obtenir des images, des feuilles de style ou d’autres fichiers ;
  • requêtes fetch/XHR pour obtenir des données d’API.

Le service worker par défaut contient une logique de cas particuliers pour les requêtes de navigation. Le service worker résout les requêtes en retournant le contenu mis en cache pour /index.html, quelle que soit l’URL demandée. Cette logique est implémentée dans la fonction onFetch à l’intérieur de service-worker.published.js.

Si votre application a certaines URL qui doivent retourner du contenu HTML rendu par le serveur, au lieu du contenu /index.html issu du cache, vous devez modifier la logique dans votre service worker. Si toutes les URL contenant /Identity/ doivent être traitées comme des requêtes uniquement en ligne standard adressées au serveur, modifiez la logique service-worker.published.jsonFetch. Recherchez le code suivant :

const shouldServeIndexHtml = event.request.mode === 'navigate';

Modifiez le code comme suit :

const shouldServeIndexHtml = event.request.mode === 'navigate'
  && !event.request.url.includes('/Identity/');

Si vous ne modifiez pas le code, quelle que soit la connectivité réseau, le service worker intercepte les requêtes pour ces URL et les résout avec /index.html.

Ajoutez à la vérification des points de terminaison supplémentaires pour les fournisseurs d’authentification externes. Dans l’exemple suivant, le point de terminaison /signin-google pour l’authentification Google est ajouté à la vérification :

const shouldServeIndexHtml = event.request.mode === 'navigate'
  && !event.request.url.includes('/Identity/')
  && !event.request.url.includes('/signin-google');

Aucune action n’est requise pour l’environnement de Development, où le contenu est toujours récupéré à partir du réseau.

Contrôle de la mise en cache des ressources

Si votre projet définit la propriété MSBuild ServiceWorkerAssetsManifest, les outils de build de Blazor créent un manifeste de ressources pour le service worker, avec le nom spécifié. Le modèle PWA par défaut produit un fichier projet contenant la propriété suivante :

<ServiceWorkerAssetsManifest>service-worker-assets.js</ServiceWorkerAssetsManifest>

Le fichier étant placé dans le répertoire de sortie wwwroot, le navigateur peut récupérer ce fichier en demandant /service-worker-assets.js. Pour afficher le contenu de ce fichier, ouvrez /bin/Debug/{TARGET FRAMEWORK}/wwwroot/service-worker-assets.js dans un éditeur de texte. Ne modifiez pas le fichier, car il est regénéré à chaque build.

Par défaut, ce manifeste liste les éléments suivants :

  • Toutes les ressources managées par Blazor, telles que les assemblys .NET et les fichiers de runtime .NET WebAssembly requis pour l’exécution hors connexion.
  • Toutes les ressources nécessaires à la publication dans le répertoire wwwroot de l’application, comme les images, les feuilles de style et les fichiers JavaScript, y compris les ressources web statiques fournies par des projets externes et des packages NuGet.

Vous pouvez contrôler lesquelles de ces ressources sont récupérées (fetch) et mises en cache par le service worker, en modifiant la logique dans onInstall dans service-worker.published.js. Par défaut, le service Worker récupère et met en cache les fichiers ayant des extensions de nom de fichier web classiques, comme .html, .css, .js et .wasm, ainsi que les types de fichiers spécifiques à Blazor WebAssembly, comme les fichiers .pdb (Toutes les versions) et .dll (ASP.NET Core dans .NET 7 ou une version antérieure).

Pour inclure des ressources supplémentaires qui ne sont pas présentes dans le répertoire wwwroot de l’application, définissez d’autres entrées MSBuild ItemGroup, comme illustré dans l’exemple suivant :

<ItemGroup>
  <ServiceWorkerAssetsManifestItem Include="MyDirectory\AnotherFile.json"
    RelativePath="MyDirectory\AnotherFile.json" AssetUrl="files/AnotherFile.json" />
</ItemGroup>

Les métadonnées AssetUrl spécifient l’URL relative de base que le navigateur doit utiliser lors de la récupération de la ressource à mettre en cache. Cela n’est pas forcément lié à son nom de fichier source d’origine sur le disque.

Important

L’ajout d’un ServiceWorkerAssetsManifestItem n’entraîne pas la publication du fichier dans le répertoire wwwroot de l’application. La sortie de publication doit être contrôlée séparément. Seul le ServiceWorkerAssetsManifestItem provoque l’affichage d’une entrée supplémentaire dans le manifeste des ressources du service worker.

Notifications Push

Comme toute autre application PWA, une application PWA Blazor WebAssembly peut recevoir des notifications Push de la part d’un serveur back-end. Le serveur peut envoyer des notifications Push à tout moment, même lorsque l’utilisateur n’interagit pas avec l’application. Par exemple, des notifications Push peuvent être envoyées quand un autre utilisateur effectue une action pertinente.

Le mécanisme d’envoi d’une notification Push est totalement indépendant de Blazor WebAssembly, car il est implémenté par le serveur back-end qui peut utiliser n’importe quelle technologie. Si vous souhaitez envoyer des notifications Push à partir d’un serveur ASP.NET Core, envisagez d’utiliser une technique similaire à l’approche adoptée dans l’atelier Blazing Pizza.

Le mécanisme de réception et d’affichage d’une notification Push sur le client est également indépendant de Blazor WebAssembly, car il est implémenté dans le fichier JavaScript du service worker. Pour obtenir un exemple, consultez l’approche utilisée dans l’atelier Blazing Pizza.

Mises en garde relatives aux applications PWA exécutables hors connexion

Les applications n’ont pas vocation à être toutes exécutables hors connexion. La prise en charge du mode hors connexion accroît la complexité de manière significative, alors qu’elle n’est pas toujours pertinente pour les cas d’usage requis.

La prise en charge du mode hors connexion est généralement pertinente uniquement :

  • Si le magasin de données principal est local dans le navigateur. Par exemple, l’approche est pertinente dans une application avec une interface utilisateur pour un appareil IoT qui stocke des données dans localStorage ou IndexedDB.
  • Si l’application a une grosse charge de travail pour récupérer (fetch) et mettre en cache les données d’API back-end relatives à chacun des utilisateurs afin que ceux-ci puissent naviguer dans les données en mode hors connexion. Si l’application doit prendre en charge la modification, auquel cas un système de suivi des changements et de synchronisation des données avec le serveur back-end doit être créé.
  • Si l’objectif est de garantir le chargement immédiat de l’application, quelles que soient les conditions réseau. Implémentez une expérience utilisateur appropriée autour des requêtes d’API back-end pour afficher la progression des requêtes et présenter un comportement correct en cas d’échec des requêtes en raison d’une indisponibilité du réseau.

En outre, les applications PWA exécutables hors connexion doivent faire face à diverses autres complications. Il est donc essentiel que les développeurs prennent connaissance des mises en garde données dans les sections suivantes.

Prise en charge du mode hors connexion uniquement après publication

Durant le développement, vous souhaitez généralement voir chaque modification immédiatement répercutée dans le navigateur sans avoir à passer par un processus de mise à jour en arrière-plan. C’est pourquoi le modèle PWA de Blazor permet la prise en charge du mode hors connexion uniquement après publication.

Quand vous créez une application exécutable hors connexion, tester l’application dans l’environnement de Development n’est pas suffisant. Vous devez tester l’application dans son état publié pour comprendre comment elle répond aux différentes conditions réseau.

Fin du processus de mise à jour quand l’utilisateur quitte l’application

Les mises à jour ne sont pas complètes tant que l’utilisateur n’a pas quitté tous les onglets de l’application. Comme cela a été expliqué dans la section Mises à jour en arrière-plan, une fois que vous avez déployé une mise à jour dans l’application, le navigateur récupère les fichiers du service worker qui ont été mis à jour pour commencer le processus de mise à jour.

Ce qui surprend de nombreux développeurs, c’est que, même lorsque cette mise à jour est terminée, elle n’est pas appliquée tant que l’utilisateur n’a pas quitté tous les onglets. Il ne suffit pas d’actualiser l’onglet affichant l’application, même si c’est le seul onglet encore ouvert. Tant que votre application n’est pas complètement fermée, le nouveau service worker reste dans l’état en attente d’activation. Ce comportement n’est pas propre à Blazor ; c’est un comportement standard des plateformes web.

Cela dérange souvent les développeurs qui essaient de tester les mises à jour de leurs ressources de service worker ou de celles mises en cache hors connexion. Dans les outils de développement du navigateur, vous pouvez voir quelque chose de similaire à ceci :

L’onglet « Application » de Google Chrome indique que le Service Worker de l’application est « en attente d’activation ».

Tant que la liste des « clients », qui sont des onglets ou fenêtres affichant votre application, n’est pas vide, le service worker reste en attente. Les service workers ont ce comportement afin de garantir la cohérence. La cohérence implique que toutes les ressources sont récupérées du même cache atomique.

Durant vos tests des modifications, il peut s’avérer pratique de sélectionner le lien « skipWaiting » (Ignorer l’attente), comme dans la capture d’écran précédente, puis de recharger la page. Vous pouvez automatiser ce comportement pour tous les utilisateurs en codant votre service worker pour ignorer la phase d’attente et activer immédiatement les mises à jour. Si vous ignorez la phase d’attente, vous renoncez à la garantie que les ressources soient toujours récupérées de manière cohérente à partir de la même instance de cache.

Les utilisateurs peuvent exécuter n’importe quelle version historique de l’application

Les développeurs web s’attendent généralement à ce que les utilisateurs exécutent uniquement la dernière version déployée de leur application web. C’est en effet le comportement standard dans le modèle de distribution web classique. Toutefois, une application PWA exécutable d’abord hors connexion s’apparente davantage à une application mobile native, dont les utilisateurs n’exécutent pas toujours la dernière version.

Comme nous l’avons expliqué dans la section Mises à jour en arrière-plan, après le déploiement d’une mise à jour dans votre application, chaque utilisateur existant continuera d’utiliser une version antérieure au moins une fois lors d’une découverte ultérieure, car la mise à jour effectuée en arrière-plan sera activée seulement quand l’utilisateur aura totalement quitté l’application. De plus, la version antérieure utilisée n’est pas obligatoirement la précédente version que vous aviez déployée. La version antérieure peut être n’importe laquelle des versions historiques, en fonction de la date de la dernière mise à jour faite par l’utilisateur.

Cela peut poser un problème si les composants front-end et back-end de votre application exigent un accord sur le schéma pour les requêtes d’API. Vous ne devez pas déployer de modifications de schéma d’API présentant une incompatibilité descendante avant d’être sûr que tous les utilisateurs ont effectué la mise à niveau. Vous pouvez sinon empêcher les utilisateurs d’utiliser des versions antérieures de l’application qui ne sont pas compatibles. Cette exigence de scénario est identique pour les applications mobiles natives. Si vous déployez un changement cassant dans des API serveur, l’application cliente cesse de fonctionner pour les utilisateurs qui n’ont pas encore fait la mise à jour.

Faites votre possible pour ne pas déployer de changements cassants dans vos API back-end. Si vous ne pouvez pas faire autrement, essayez d’utiliser des API de service worker standard telles que ServiceWorkerRegistration pour déterminer si l’application est à jour et, si ce n’est pas le cas, pour empêcher son utilisation.

Interférence avec les pages rendues par le serveur

Comme décrit dans la section Prise en charge des pages rendues par le serveur, si vous souhaitez contourner le comportement du service worker qui consiste à retourner le contenu /index.html pour toutes les requêtes de navigation, modifiez la logique dans votre service worker.

Tout le contenu du manifeste des ressources du service worker est mis en cache par défaut

Comme vous l’avez vu dans la section Contrôle de la mise en cache des ressources, le fichier service-worker-assets.js est généré au moment de la build et il liste toutes les ressources que le service worker doit récupérer (fetch) et mettre en cache.

Étant donné que cette liste inclut par défaut tout ce qui est envoyé vers wwwroot, y compris le contenu fourni par des packages et projets externes, vous devez être prudent dans le choix du contenu mis dans cette liste. Si le répertoire wwwroot contient des millions d’images, le service worker tentera de récupérer et mettre en cache la totalité de ces images, ce qui entraînera une consommation de bande passante excessive et probablement l’échec de la tentative.

Implémentez une logique arbitraire pour contrôler quel sous-ensemble du contenu du manifeste doit être récupéré et mis en cache, en modifiant la fonction onInstall dans service-worker.published.js.

Interaction avec l’authentification

Le modèle PWA peut être utilisé conjointement avec l’authentification. Une application PWA exécutable hors connexion peut également prendre en charge l’authentification lorsque l’utilisateur dispose d’une connectivité réseau initiale.

Quand un utilisateur n’a pas de connectivité réseau, il ne peut pas s’authentifier ni obtenir de jetons d’accès. Par défaut, toute tentative d’accès à la page de connexion sans accès réseau génère un message « erreur réseau ». Vous devez concevoir un flux d’interface utilisateur qui permet à l’utilisateur d’effectuer des tâches utiles en mode hors connexion sans qu’il ait besoin de s’authentifier ou d’obtenir des jetons d’accès. Une autre solution est de concevoir l’application pour qu’elle échoue correctement lorsque le réseau n’est pas disponible. Si l’application ne peut pas être conçue de façon à prendre en charge ces scénarios, il est préférable de ne pas fournir de mode hors connexion.

Quand une application conçue pour une utilisation en ligne et hors connexion est de nouveau en ligne :

  • L’application peut avoir besoin de provisionner un nouveau jeton d’accès.
  • L’application doit détecter si un autre utilisateur est connecté au service afin qu’elle puisse appliquer les opérations sur le compte de l’utilisateur qui avaient été faites en mode hors connexion.

Pour créer une application PWA exécutable hors connexion qui interagit avec l’authentification :

  • Remplacez AccountClaimsPrincipalFactory<TAccount> par une fabrique qui enregistre le dernier utilisateur connecté et qui utilise l’utilisateur enregistré lorsque l’application est hors connexion.
  • Mettez les opérations en file d’attente pendant que l’application est hors connexion et appliquez-les une fois que l’application est de nouveau en ligne.
  • À la déconnexion, supprimez l’utilisateur enregistré.

L’exemple d’application CarChecker illustre les approches vues plus haut. Consultez les informations sur les composants suivants de l’application :

  • OfflineAccountClaimsPrincipalFactory (Client/Data/OfflineAccountClaimsPrincipalFactory.cs)
  • LocalVehiclesStore (Client/Data/LocalVehiclesStore.cs)
  • Composant LoginStatus (Client/Shared/LoginStatus.razor)

Ressources supplémentaires