Interopérabilité JavaScript dans ASP.NET Core Blazor (interopérabilité JS)

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 Blazor peut appeler des fonctions JavaScript (JS) à partir de méthodes .NET et de méthodes .NET issues de fonctions JS. Ces scénarios sont appelés interopérabilité JavaScript (interopérabilité JS).

D’autres conseils d’interopérabilité JS sont fournis dans les articles suivants :

Remarque

L’API d’interopérabilité JavaScript[JSImport]/[JSExport] est disponible pour les composants côté client dans ASP.NET Core dans .NET 7 ou ultérieur.

Pour plus d’informations, consultez interopérabilité JSImport/JSExport JavaScript avec Blazor ASP.NET Core.

Compression pour les composants de serveur interactifs avec des données non approuvées

Avec la compression (activée par défaut), évitez de créer des composants interactifs côté serveur (authentifiés/autorisés) sécurisés qui affichent des données provenant de sources non approuvées. Les sources non approuvées incluent les paramètres de routage, les chaînes de requête, les données de JS l’interopérabilité, et toute autre source de données qu’un utilisateur tiers peut contrôler (bases de données, services externes). Pour plus d’informations, consultez Conseils pour ASP.NET Core BlazorSignalR et Conseils d’atténuation des menaces pour le rendu interactif côté serveur de ASP.NET Core Blazor.

Package d’abstractions et de fonctionnalités JavaScript

Le package @microsoft/dotnet-js-interop (npmjs.com) (package NuGet Microsoft.JSInterop) fournit des abstractions et des fonctionnalités pour l’interopérabilité entre le code .NET et JavaScript (JS). La source de référence est disponible dans le référentiel GitHub dotnet/aspnetcore (dossier/src/JSInterop ). Pour plus d’informations, consultez le fichier README.mdréférentiel GitHub.

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).

Ressources supplémentaires pour écrire des scripts d’interopérabilité JS dans TypeScript :

Interaction avec le DOM

Mutez uniquement le modèle DOM avec JavaScript (JS) quand l’objet n’interagit pas avec Blazor. Blazor gère les représentations du modèle DOM et interagit directement avec les objets DOM. Si un élément rendu par Blazor est modifié en externe à l’aide de JS directement ou via l’interopérabilité JS, le modèle DOM peut ne plus correspondre à la représentation interne de Blazor, ce qui peut entraîner un comportement non défini. Un comportement non défini peut simplement interférer avec la présentation d’éléments ou leurs fonctions, mais peut également introduire des risques de sécurité pour l’application ou le serveur.

Cette recommandation s’applique non seulement à votre propre code d’interopérabilité JS, mais également à toutes les bibliothèques JS que l’application utilise, y compris tout ce qui est fourni par une infrastructure tierce, telle que Bootstrap JS et jQuery.

Dans quelques exemples de documentation, l’interopérabilité JS est utilisée pour muter un élément à des fins d’illustration uniquement dans le cadre d’un exemple. Dans ces cas, un avertissement apparaît dans le texte.

Pour plus d’informations, consultez Appeler des fonctions JavaScript à partir de méthodes .NET dans ASP.NET Core Blazor.

Appels JavaScript asynchrones

Les appels d’interopérabilité JS sont asynchrones par défaut, que le code appelé soit synchrone ou asynchrone. Les appels sont asynchrones par défaut pour garantir que les composants sont compatibles entre les modes de rendu côté serveur et côté client. Lors de l’adoption du rendu côté serveur, les JSappels interop doivent être asynchrones car ils sont envoyés via une connexion réseau. Pour les applications qui adoptent exclusivement le rendu côté client, les JSappels interop synchrones sont pris en charge.

Sérialisation d’objets

Blazor utilise System.Text.Json pour la sérialisation avec les exigences et les comportements par défaut suivants :

  • Les types doivent avoir un constructeur par défaut, les accesseurs get/set doivent être publics et les champs ne sont jamais sérialisés.
  • La sérialisation par défaut globale n’est pas personnalisable pour éviter un arrêt des bibliothèques de composants existantes, des répercussions sur les performances et la sécurité, et des baisses de fiabilité.
  • La sérialisation des noms de membres .NET entraîne des noms de clés JSON en minuscules.
  • JSON est désérialisé en tant qu’instances C# JsonElement, ce qui permet d’utiliser une casse mixte. Le cast interne pour l’affectation aux propriétés du modèle C# fonctionne comme prévu malgré les différences de casse entre les noms des clés JSON et les noms des propriétés C#.
  • Les types de frameworks complexes, tels que KeyValuePair, peuvent être découpés par l’outil IL Trimmer lors de la publication et ne pas être présents pour l’interopérabilité avec JS. Nous vous recommandons de créer des types personnalisés pour les types découpés par défaut par l’outil IL Trimmer.

L’API JsonConverter est disponible pour la sérialisation personnalisée. Les propriétés peuvent être annotées avec un attribut [JsonConverter] pour remplacer la sérialisation par défaut pour un type de données existant.

Pour plus d’informations, consultez les ressources suivantes dans la documentation .NET :

Blazor prend en charge l’interopérabilité JS des tableaux d’octets optimisés, qui évite l’encodage/décodage des tableaux d’octets en Base64. L’application peut appliquer une sérialisation personnalisée et transmettre les octets obtenus. Pour plus d’informations, consultez Appeler des fonctions JavaScript à partir de méthodes .NET dans ASP.NET Core Blazor.

Blazor prend en charge l’interopérabilité JS non marshallée quand un volume élevé d’objets .NET est rapidement sérialisé ou quand des objets .NET volumineux ou de nombreux objets .NET doivent être sérialisés. Pour plus d’informations, consultez Appeler des fonctions JavaScript à partir de méthodes .NET dans ASP.NET Core Blazor.

Tâches de nettoyage de modèle DOM lors de la suppression des composants

N’exécutez pas de code d’interopérabilité JS pour les tâches de nettoyage DOM pendant la suppression des composants. Utilisez plutôt le modèle MutationObserver en JavaScript (JS) sur le client pour les raisons suivantes :

  • Le composant a peut-être été supprimé du DOM au moment où votre code de nettoyage s’exécute dans Dispose{Async}.
  • Lors du rendu côté serveur, le moteur de Blazorrendu peut avoir été éliminé par le framework au moment où votre code de nettoyage s’exécute dans Dispose{Async}.

Le modèle MutationObserver vous permet d’exécuter une fonction lorsqu’un élément est supprimé du DOM.

Dans l’exemple suivant, le composant DOMCleanup :

  • Contient un <div> avec un id de cleanupDiv. L’élément <div> est supprimé du DOM, ainsi que le reste du balisage DOM du composant lorsque le composant est supprimé du DOM.
  • Charge la classe DOMCleanupJS à partir du fichier DOMCleanup.razor.js et appelle sa fonction de createObserver pour configurer le rappel MutationObserver. Ces tâches sont effectuées dans la OnAfterRenderAsyncméthode de cycle de vie.

DOMCleanup.razor:

@page "/dom-cleanup"
@implements IAsyncDisposable
@inject IJSRuntime JS

<h1>DOM Cleanup Example</h1>

<div id="cleanupDiv"></div>

@code {
    private IJSObjectReference? module;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            module = await JS.InvokeAsync<IJSObjectReference>(
                "import", "./Components/Pages/DOMCleanup.razor.js");

            await module.InvokeVoidAsync("DOMCleanup.createObserver");
        }
    }

    async ValueTask IAsyncDisposable.DisposeAsync()
    {
        if (module is not null)
        {
            await module.DisposeAsync();
        }
    }
}

Dans l’exemple suivant, le rappel MutationObserver est exécuté chaque fois qu’une modification DOM se produit. Exécutez votre code de nettoyage lorsque l’instruction if confirme que l’élément cible (cleanupDiv) a été supprimé (if (targetRemoved) { ... }). Il est important de déconnecter et de supprimer la MutationObserver pour éviter une fuite de mémoire après l’exécution de votre code de nettoyage.

DOMCleanup.razor.js placé côte à côte avec le composant DOMCleanup précédent :

export class DOMCleanup {
  static observer;

  static createObserver() {
    const target = document.querySelector('#cleanupDiv');

    this.observer = new MutationObserver(function (mutations) {
      const targetRemoved = mutations.some(function (mutation) {
        const nodes = Array.from(mutation.removedNodes);
        return nodes.indexOf(target) !== -1;
      });

      if (targetRemoved) {
        // Cleanup resources here
        // ...

        // Disconnect and delete MutationObserver
        this.observer && this.observer.disconnect();
        delete this.observer;
      }
    });

    this.observer.observe(target.parentNode, { childList: true });
  }
}

window.DOMCleanup = DOMCleanup;

Appels d’interopérabilité JavaScript sans circuit

Cette section s’applique uniquement aux applications côté serveur.

Les appels d’interopérabilité JavaScript (JS) ne peuvent pas être émis après la déconnexion d’un circuit SignalR. Sans circuit lors de l’élimination du composant ou à tout autre moment où un circuit n’existe pas, les appels de méthode suivants échouent et journalisent un message indiquant que le circuit est déconnecté en tant que JSDisconnectedException :

Pour éviter la journalisation JSDisconnectedException ou pour journaliser des informations personnalisées, interceptez l’exception dans une instruction try-catch.

Pour l’exemple de suppression de composant suivant :

  • Le composant implémente IAsyncDisposable.
  • objInstance est une IJSObjectReference.
  • JSDisconnectedException est intercepté et non journalisé.
  • Si vous le souhaitez, vous pouvez enregistrer des informations personnalisées dans l’instruction catch au niveau de journal de votre choix. L’exemple suivant ne journalise pas les informations personnalisées, car il part du principe que le développeur ne se soucie pas du moment ou de l’endroit où les circuits sont déconnectés lors de l’élimination des composants.
async ValueTask IAsyncDisposable.DisposeAsync()
{
    try
    {
        if (objInstance is not null)
        {
            await objInstance.DisposeAsync();
        }
    }
    catch (JSDisconnectedException)
    {
    }
}

Si vous devez nettoyer vos propres objets JS ou exécuter un autre code JS sur le client une fois qu’un circuit est perdu, utilisez le modèle MutationObserver dans JS sur le client. Le modèle MutationObserver vous permet d’exécuter une fonction lorsqu’un élément est supprimé du DOM.

Pour plus d’informations, consultez les articles suivants :

Fichiers JavaScript mis en cache

Les fichiers JavaScript (JS) et d’autres ressources statiques ne sont généralement pas mis en cache sur les clients pendant le développement dans l’environnement Development. Au cours du développement, les demandes de ressources statiques incluent l’en-tête Cache-Control avec une valeur de no-cache ou max-age avec une valeur nulle (0).

Pendant la production dans l’environnement Production, les fichiers JS sont généralement mis en cache par les clients.

Pour désactiver la mise en cache côté client dans les navigateurs, les développeurs adoptent généralement l’une des approches suivantes :

Pour plus d'informations, consultez les pages suivantes :

Limites de taille sur les appels d’interopérabilité JavaScript

Cette section s’applique uniquement aux composants interactifs dans les applications côté serveur. Pour les composants côté client, le cadre n’impose pas de limite à la taille des entrées et sorties interop JavaScript (JS).

Pour les composants interactifs dans les applications côté serveur, JS appels d’interopérabilité passant des données du client au serveur sont limités par la taille maximale des messages entrants SignalR autorisées pour les méthodes hub, appliquées par HubOptions.MaximumReceiveMessageSize (valeur par défaut : 32 Ko). Les messages JS vers .NET SignalR supérieurs à MaximumReceiveMessageSize génèrent une erreur. Le framework n’impose pas de limite à la taille d’un message SignalR du hub vers un client. Pour plus d’informations sur la limite de taille, les messages d’erreur et les conseils sur la gestion des limites de taille des messages, consultez ASP.NET guide de BlazorSignalR Core.

Déterminer où l’application est en cours d’exécution

S’il est pertinent pour l’application de savoir où le code est en cours d’exécution pour les appels d’interopérabilité JS, utilisez OperatingSystem.IsBrowser pour déterminer si le composant s’exécute dans le contexte du navigateur sur WebAssembly.