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 9 de cet article.
Avertissement
Cette version d’ASP.NET Core n’est plus prise en charge. Pour plus d’informations, consultez la stratégie de support .NET et .NET Core. Pour la version actuelle, consultez la version .NET 9 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 9 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 :
- Appeler des fonctions JavaScript à partir de méthodes .NET dans ASP.NET Core Blazor
- Appeler des méthodes .NET à partir de fonctions JavaScript dans ASP.NET Core Blazor
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 ASP.NET Core Blazor.
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.md
ré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 :
- TypeScript
- Tutoriel : Créer une application ASP.NET Core avec TypeScript dans Visual Studio
- Gérer les packages npm dans Visual Studio
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.
Classe JavaScript avec un champ de fonction de type
Une classe JavaScript avec un champ de fonction de type n’est pas prise en charge par l’interopérabilité BlazorJS. Utilisez des fonctions Javascript dans les classes.
Non pris en charge : dans la classe suivante, comme champ de fonction de type, GreetingHelpers.sayHello
n’est pas découvert par l’interopérabilité JS de Blazor et ne peut pas être exécuté à partir du code C# :
export class GreetingHelpers {
sayHello = function() {
...
}
}
Pris en charge :dans la classe suivante, en tant que fonction, GreetingHelpers.sayHello
est prise en charge :
export class GreetingHelpers {
sayHello() {
...
}
}
Les fonctions de flèche sont également prises en charge :
export class GreetingHelpers {
sayHello = () => {
...
}
}
Éviter les gestionnaires d’événements inline
Une fonction JavaScript peut être appelée directement à partir d’un gestionnaire d’événements inline. Dans l’exemple suivant, alertUser
est une fonction JavaScript appelée lorsque le bouton est sélectionné par l’utilisateur :
<button onclick="alertUser">Click Me!</button>
Toutefois, l’utilisation de gestionnaires d’événements inline est un choix de conception médiocre pour l’appel de fonctions JavaScript :
- Le mélange de balises HTML et de codes JavaScript conduit souvent à du code non durable.
- L’exécution du gestionnaire d’événements inline peut être bloquée par une stratégie de sécurité du contenu (CSP) (documentation MDN).
Nous vous recommandons d’éviter les gestionnaires d’événements inline en faveur des approches qui attribuent des gestionnaires en JavaScript avec addEventListener
, comme l’illustre l’exemple suivant :
AlertUser.razor.js
:
export function alertUser() {
alert('The button was selected!');
}
export function addHandlers() {
const btn = document.getElementById("btn");
btn.addEventListener("click", alertUser);
}
AlertUser.razor
:
@page "/alert-user"
@implements IAsyncDisposable
@inject IJSRuntime JS
<h1>Alert User</h1>
<p>
<button id="btn">Click Me!</button>
</p>
@code {
private IJSObjectReference? module;
protected async override Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
module = await JS.InvokeAsync<IJSObjectReference>("import",
"./Components/Pages/AlertUser.razor.js");
await module.InvokeVoidAsync("addHandlers");
}
}
async ValueTask IAsyncDisposable.DisposeAsync()
{
if (module is not null)
{
try
{
await module.DisposeAsync();
}
catch (JSDisconnectedException)
{
}
}
}
}
Pour plus d’informations, consultez les ressources suivantes :
- Emplacement du JavaScript dans les applications ASP.NET CoreBlazor
- Présentation des événements (documentation MDN)
Appels JavaScript asynchrones
Les appels d’interopérabilité JS sont asynchrones, que le code appelé soit synchrone ou asynchrone. Les appels sont asynchrones 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.
Pour plus d’informations, consultez les articles suivants :
Pour plus d’informations, consultez Appeler des fonctions JavaScript à partir de méthodes .NET dans ASP.NET Core Blazor.
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 l’outil IL Trimmer.
- Blazor s’appuie toujours sur la réflexion pour la sérialisation JSON, y compris lors de l’utilisation de la génération de source de C#. La définition de
JsonSerializerIsReflectionEnabledByDefault
surfalse
dans le fichier projet de l’application entraîne une erreur lors de la tentative de sérialisation.
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 :
- Sérialisation et désérialisation JSON (marshalling et unmarshalling) dans .NET
- Comment personnaliser les noms et valeurs de propriétés avec
System.Text.Json
- Comment écrire des convertisseurs personnalisés pour la sérialisation JSON (marshaling) dans .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 unid
decleanupDiv
. L’élément<div>
est supprimé du DOM, ainsi que le rest du balisage DOM du composant lorsque le composant est supprimé du DOM. - Charge la classe
DOMCleanup
JS à partir du fichierDOMCleanup.razor.js
et appelle sa fonction decreateObserver
pour configurer le rappelMutationObserver
. Ces tâches sont effectuées dans laOnAfterRenderAsync
mé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)
{
try
{
await module.DisposeAsync();
}
catch (JSDisconnectedException)
{
}
}
}
}
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 Blazorla déconnexion du SignalR circuit. 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 :
- Appels de méthode d’interopérabilité JS
Dispose
/DisposeAsync
appelle sur n’importe quel IJSObjectReference.
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 côté serveur implémente IAsyncDisposable.
module
est un IJSObjectReference JS module.- 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 (module is not null)
{
await module.DisposeAsync();
}
}
catch (JSDisconnectedException)
{
}
}
Si vous devez nettoyer vos propres JS objets ou exécuter un autre JS code sur le client une fois qu’un circuit est perdu dans une application côté Blazor serveur, utilisez le MutationObserver
modèle dans JS 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 :
- Gérer les erreurs dans les applications ASP.NET Core Blazor : la section Interopérabilité JavaScript traite de la gestion des erreurs dans les scénarios d’interopérabilité JS.
- Cycle de vie des composants ASP.NET Core Razor : la section Suppression des composants avec
IDisposable
etIAsyncDisposable
décrit comment implémenter des modèles d’élimination dans les composants Razor.
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 :
- Désactivez la mise en cache quand la console des outils de développement du navigateur est ouverte. Vous trouverez des conseils dans la documentation des outils de développement de chaque chargé de maintenance du navigateur :
- Effectuez une actualisation manuelle dans le navigateur de n’importe quelle page web de l’application Blazor pour recharger les fichiers JS à partir du serveur. Le middleware (intergiciel) de mise en cache HTTP d’ASP.NET Core respecte toujours un en-tête
Cache-Control
valide sans cache, envoyé par un client.
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.