Note
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier les répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de changer de répertoire.
Note
Ceci n’est pas la dernière version de cet article. Pour la version actuelle, consultez la version .NET 10 de cet article.
Warning
Cette version d'ASP.NET Core n'est plus prise en charge. Pour plus d’informations, consultez la stratégie de prise en charge de .NET et .NET Core. Pour la version actuelle, consultez la version .NET 9 de cet article.
Cette rubrique explique comment appeler des méthodes .NET depuis JavaScript (JS).
Pour savoir comment appeler des fonctions JS depuis .NET, veuillez consulter la section Appeler des fonctions JavaScript depuis des méthodes .NET dans ASP.NET Core Blazor.
Appeler une méthode .NET statique
Pour appeler une méthode .NET statique depuis JavaScript (JS), utilisez les fonctions JS :
-
DotNet.invokeMethodAsync(recommandée) : asynchrone pour les composants côté serveur et côté client. -
DotNet.invokeMethod: synchrone pour les composants côté client uniquement.
Indiquez le nom de l’assembly contenant la méthode, l’identifiant de la méthode .NET statique et les éventuels arguments.
Dans l’exemple suivant :
- L’espace réservé
{PACKAGE ID/ASSEMBLY NAME}correspond à l’ID de package du projet (<PackageId>dans le fichier projet) pour une bibliothèque ou au nom de l’assembly pour une application. - L’espace réservé
{.NET METHOD ID}correspond à l’identifiant de la méthode .NET. - Les espaces réservés
{ARGUMENTS}sont des arguments facultatifs, séparés par des virgules, à transmettre à la méthode, chacun devant être sérialisable en JSON.
DotNet.invokeMethodAsync('{PACKAGE ID/ASSEMBLY NAME}', '{.NET METHOD ID}', {ARGUMENTS});
DotNet.invokeMethodAsync retourne un JS Promise représentant le résultat de l’opération.
DotNet.invokeMethod (composants côté client) retourne le résultat de l’opération.
Important
Pour les composants côté serveur, nous recommandons la fonction asynchrone (invokeMethodAsync) plutôt que la version synchrone (invokeMethod).
La méthode .NET doit être publique, statique et posséder [JSInvokable] comme attribut.
Dans l’exemple suivant :
- L’espace réservé
{<T>}indique le type de retour, requis uniquement pour les méthodes retournant une valeur. - L’espace réservé
{.NET METHOD ID}correspond à l’identifiant de la méthode.
@code {
[JSInvokable]
public static Task{<T>} {.NET METHOD ID}()
{
...
}
}
Note
L’appel de méthodes génériques ouvertes n’est pas pris en charge avec les méthodes .NET statiques, mais il l’est avec les méthodes d’instance. Pour plus d’informations, veuillez consulter la section Appeler des méthodes de classe générique .NET.
Dans le composant suivant, la méthode C# ReturnArrayAsync retourne un tableau int.
[JSInvokable] est l' attribut appliqué à la méthode, ce qui la rend appelable par JS.
CallDotnet1.razor :
@page "/call-dotnet-1"
@implements IAsyncDisposable
@inject IJSRuntime JS
<PageTitle>Call .NET 1</PageTitle>
<h1>Call .NET Example 1</h1>
<p>
<button id="btn">Trigger .NET static method</button>
</p>
<p>
See the result in the developer tools console.
</p>
@code {
private IJSObjectReference? module;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
module = await JS.InvokeAsync<IJSObjectReference>("import",
"./Components/Pages/CallDotnet1.razor.js");
await module.InvokeVoidAsync("addHandlers");
}
}
[JSInvokable]
public static Task<int[]> ReturnArrayAsync() =>
Task.FromResult(new int[] { 11, 12, 13 });
async ValueTask IAsyncDisposable.DisposeAsync()
{
if (module is not null)
{
try
{
await module.DisposeAsync();
}
catch (JSDisconnectedException)
{
}
}
}
}
CallDotnet1.razor.js :
export function returnArrayAsync() {
DotNet.invokeMethodAsync('BlazorSample', 'ReturnArrayAsync')
.then(data => {
console.log(data);
});
}
export function addHandlers() {
const btn = document.getElementById("btn");
btn.addEventListener("click", returnArrayAsync);
}
La fonction addHandlersJS ajoute un événement click au bouton. La fonction returnArrayAsyncJS est affectée comme gestionnaire.
La fonction returnArrayAsyncJS appelle la méthode .NET ReturnArrayAsync du composant, qui journalise le résultat dans la console des outils de développement web du navigateur.
BlazorSample correspond au nom de l’assembly de l’application.
CallDotnet1.razor :
@page "/call-dotnet-1"
@implements IAsyncDisposable
@inject IJSRuntime JS
<PageTitle>Call .NET 1</PageTitle>
<h1>Call .NET Example 1</h1>
<p>
<button id="btn">Trigger .NET static method</button>
</p>
<p>
See the result in the developer tools console.
</p>
@code {
private IJSObjectReference? module;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
module = await JS.InvokeAsync<IJSObjectReference>("import",
"./Components/Pages/CallDotnet1.razor.js");
await module.InvokeVoidAsync("addHandlers");
}
}
[JSInvokable]
public static Task<int[]> ReturnArrayAsync() =>
Task.FromResult(new int[] { 11, 12, 13 });
async ValueTask IAsyncDisposable.DisposeAsync()
{
if (module is not null)
{
try
{
await module.DisposeAsync();
}
catch (JSDisconnectedException)
{
}
}
}
}
CallDotnet1.razor.js :
export function returnArrayAsync() {
DotNet.invokeMethodAsync('BlazorSample', 'ReturnArrayAsync')
.then(data => {
console.log(data);
});
}
export function addHandlers() {
const btn = document.getElementById("btn");
btn.addEventListener("click", returnArrayAsync);
}
La fonction addHandlersJS ajoute un événement click au bouton. La fonction returnArrayAsyncJS est affectée comme gestionnaire.
La fonction returnArrayAsyncJS appelle la méthode .NET ReturnArrayAsync du composant, qui journalise le résultat dans la console des outils de développement web du navigateur.
BlazorSample correspond au nom de l’assembly de l’application.
CallDotNetExample1.razor :
@page "/call-dotnet-example-1"
<h1>Call .NET Example 1</h1>
<p>
<button onclick="returnArrayAsync()">
Trigger .NET static method
</button>
</p>
@code {
[JSInvokable]
public static Task<int[]> ReturnArrayAsync()
{
return Task.FromResult(new int[] { 1, 2, 3 });
}
}
CallDotNetExample1.razor :
@page "/call-dotnet-example-1"
<h1>Call .NET Example 1</h1>
<p>
<button onclick="returnArrayAsync()">
Trigger .NET static method
</button>
</p>
@code {
[JSInvokable]
public static Task<int[]> ReturnArrayAsync()
{
return Task.FromResult(new int[] { 1, 2, 3 });
}
}
CallDotNetExample1.razor :
@page "/call-dotnet-example-1"
<h1>Call .NET Example 1</h1>
<p>
<button onclick="returnArrayAsync()">
Trigger .NET static method
</button>
</p>
@code {
[JSInvokable]
public static Task<int[]> ReturnArrayAsync()
{
return Task.FromResult(new int[] { 1, 2, 3 });
}
}
CallDotNetExample1.razor :
@page "/call-dotnet-example-1"
<h1>Call .NET Example 1</h1>
<p>
<button onclick="returnArrayAsync()">
Trigger .NET static method
</button>
</p>
@code {
[JSInvokable]
public static Task<int[]> ReturnArrayAsync()
{
return Task.FromResult(new int[] { 1, 2, 3 });
}
}
L’attribut HTML <button> de l’élément onclick correspond à l’attribution du gestionnaire d’événement onclick de JavaScript pour le traitement des événements click, et non à l’attribut de directive Blazor de @onclick. La fonction returnArrayAsyncJS est affectée comme gestionnaire.
La fonction returnArrayAsyncJS suivante appelle la méthode .NET ReturnArrayAsync du composant, qui journalise le résultat dans la console des outils de développement web du navigateur.
BlazorSample correspond au nom de l’assembly de l’application.
<script>
window.returnArrayAsync = () => {
DotNet.invokeMethodAsync('BlazorSample', 'ReturnArrayAsync')
.then(data => {
console.log(data);
});
};
</script>
Note
Pour des conseils généraux concernant l’emplacement JS et nos recommandations pour les applications de production, veuillez consulter la section Emplacement JavaScript dans les applications ASP.NET Core Blazor.
Lorsque le bouton Trigger .NET static method est sélectionné, la sortie de la console des outils de développement du navigateur affiche les données du tableau. Le format des données de sortie varie légèrement selon les navigateurs. Voici un exemple montrant le format utilisé par Microsoft Edge :
Array(3) [ 11, 12, 13 ]
Transmettez des données à une méthode .NET lors de l’appel de la fonction invokeMethodAsync en passant les données sous forme d’arguments.
Pour démontrer la transmission de données à .NET, transmettez une position de départ à la méthode ReturnArrayAsync où la méthode est appelée dans JS :
export function returnArrayAsync() {
DotNet.invokeMethodAsync('BlazorSample', 'ReturnArrayAsync', 14)
.then(data => {
console.log(data);
});
}
<script>
window.returnArrayAsync = () => {
DotNet.invokeMethodAsync('BlazorSample', 'ReturnArrayAsync', 14)
.then(data => {
console.log(data);
});
};
</script>
La méthode ReturnArrayAsync appelable du composant reçoit la position de départ et construit le tableau à partir de celle-ci. Le tableau est retourné pour journalisation dans la console :
[JSInvokable]
public static Task<int[]> ReturnArrayAsync(int startPosition) =>
Task.FromResult(Enumerable.Range(startPosition, 3).ToArray());
Après la re-compilation de l’application et l’actualisation du navigateur, la sortie suivante apparaît dans la console du navigateur lorsque le bouton est sélectionné :
Array(3) [ 14, 15, 16 ]
L’identifiant de la méthode .NET pour l’appel JS est le nom de la méthode .NET, mais vous pouvez spécifier un identifiant différent à l’aide du constructeur d’attribut [JSInvokable]. Dans l’exemple suivant, DifferentMethodName est l’identifiant de méthode affecté à la méthode ReturnArrayAsync :
[JSInvokable("DifferentMethodName")]
Dans l’appel à DotNet.invokeMethodAsync (composants côté serveur ou côté client) ou à DotNet.invokeMethod (composants côté client uniquement), appelez DifferentMethodName pour exécuter la méthode .NET ReturnArrayAsync :
DotNet.invokeMethodAsync('BlazorSample', 'DifferentMethodName');-
DotNet.invokeMethod('BlazorSample', 'DifferentMethodName');(composants côté client uniquement)
Note
L’exemple de méthode ReturnArrayAsync de cette section retourne le résultat d’un Task sans utiliser explicitement les mots-clés C# async et await. Le codage des méthodes avec async et await est typique des méthodes utilisant le mot-clé await pour retourner la valeur d’opérations asynchrones.
Méthode ReturnArrayAsync composée avec les mots-clés async et await :
[JSInvokable]
public static async Task<int[]> ReturnArrayAsync() =>
await Task.FromResult(new int[] { 11, 12, 13 });
Pour plus d’informations, veuillez consulter la section Programmation asynchrone avec async et await du guide C#.
Créer des références de données et d’objet JavaScript à transmettre à .NET
Appelez DotNet.createJSObjectReference(jsObject) pour construire une référence d’objet JS afin de la transmettre à .NET, où jsObject est le JS Object utilisé pour créer la référence d’objet JS. L’exemple suivant transmet une référence à l’objet non sérialisable window à .NET, qui la reçoit dans la méthode C# ReceiveWindowObject sous la forme d’un IJSObjectReference :
DotNet.invokeMethodAsync('{PACKAGE ID/ASSEMBLY NAME}', 'ReceiveWindowObject',
DotNet.createJSObjectReference(window));
[JSInvokable]
public static void ReceiveWindowObject(IJSObjectReference objRef)
{
...
}
Dans l’exemple précédent, l’espace réservé {PACKAGE ID/ASSEMBLY NAME} correspond à l’ID de package du projet (<PackageId> dans le fichier projet) pour une bibliothèque ou au nom de l’assembly pour une application.
Note
L’exemple précédent ne nécessite pas la suppression du JSObjectReference, car aucune référence à l’objet window n’est conservée dans JS.
Le maintien d’une référence à un JSObjectReference nécessite sa suppression pour éviter les fuites de mémoire JS côté client. L’exemple suivant refactorise le code précédent pour capturer une référence au JSObjectReference, suivi d’un appel à DotNet.disposeJSObjectReference() pour supprimer la référence :
var jsObjectReference = DotNet.createJSObjectReference(window);
DotNet.invokeMethodAsync('{PACKAGE ID/ASSEMBLY NAME}', 'ReceiveWindowObject', jsObjectReference);
DotNet.disposeJSObjectReference(jsObjectReference);
Dans l’exemple précédent, l’espace réservé {PACKAGE ID/ASSEMBLY NAME} correspond à l’ID de package du projet (<PackageId> dans le fichier projet) pour une bibliothèque ou au nom de l’assembly pour une application.
Appelez DotNet.createJSStreamReference(streamReference) pour construire une référence de flux JS afin de la transmettre à .NET, où streamReference est un ArrayBuffer, Blob ou tout tableau typé (type array), tel que Uint8Array ou Float32Array, utilisé pour créer la référence de flux JS.
Appeler une méthode .NET d’instance
Pour appeler une méthode .NET d’instance depuis JavaScript (JS) :
Transmettez l’instance .NET par référence à JS en enveloppant l’instance dans un DotNetObjectReference et en appelant Create dessus.
Appelez une méthode .NET d’instance depuis JS à l’aide de
invokeMethodAsync(recommandé) ou deinvokeMethod(composants côté client uniquement) depuis l’instance transmise DotNetObjectReference. Transmettez l’identifiant de la méthode .NET d’instance et les arguments éventuels. L’instance .NET peut également être transmise en tant qu’argument lors de l’appel d’autres méthodes .NET depuis JS.Dans l’exemple suivant :
-
dotNetHelperest un DotNetObjectReference. - L’espace réservé
{.NET METHOD ID}correspond à l’identifiant de la méthode .NET. - Les espaces réservés
{ARGUMENTS}sont des arguments facultatifs, séparés par des virgules, à transmettre à la méthode, chacun devant être sérialisable en JSON.
dotNetHelper.invokeMethodAsync('{.NET METHOD ID}', {ARGUMENTS});Note
invokeMethodAsyncetinvokeMethodn’acceptent pas de paramètre de nom d’assembly lors de l’appel d’une méthode d’instance.invokeMethodAsyncretourne un JSPromisereprésentant le résultat de l’opération.invokeMethod(composants côté client seulement) retourne le résultat de l’opération.Important
Pour les composants côté serveur, nous recommandons la fonction asynchrone (
invokeMethodAsync) plutôt que la version synchrone (invokeMethod).-
Supprimez le DotNetObjectReference.
Les sections suivantes de cette rubrique présentent diverses approches pour appeler une méthode .NET d’instance :
-
Transmettre un
DotNetObjectReferenceà une fonction JavaScript individuelle -
Transmettre un
DotNetObjectReferenceà une classe contenant plusieurs fonctions JavaScript - Appeler des méthodes de classe générique .NET
- Exemples d’instance de classe
- Classe d’assistance pour méthode .NET d’instance de composant
Éviter la suppression des méthodes .NET appelables par JavaScript
Cette section s’applique aux applications côté client avec compilation anticipée (AOT) et reliage dynamique à l’exécution activés.
Plusieurs exemples dans les sections suivantes sont basés sur une approche par instance de classe, où la méthode .NET appelable par JavaScript, marquée par [JSInvokable] comme attribut, est membre d’une classe qui n’est pas un composant Razor. Lorsque ces méthodes .NET se trouvent dans un composant Razor, elles sont protégées contre le reliage/suppression à l’exécution. Pour protéger les méthodes .NET contre la suppression hors des composants Razor, implémentez les méthodes avec DynamicDependency comme attribut sur le constructeur de la classe, comme le montre l’exemple suivant :
using System.Diagnostics.CodeAnalysis;
using Microsoft.JSInterop;
public class ExampleClass {
[DynamicDependency(nameof(ExampleJSInvokableMethod))]
public ExampleClass()
{
}
[JSInvokable]
public string ExampleJSInvokableMethod()
{
...
}
}
Pour plus d’informations, veuillez consulter la section Préparer des bibliothèques .NET à la suppression : DynamicDependency.
Transmettre un DotNetObjectReference à une fonction JavaScript individuelle
L’exemple de cette section montre comment transmettre un DotNetObjectReference à une fonction JavaScript (JS) individuelle.
La fonction sayHello1JS suivante reçoit un DotNetObjectReference et appelle invokeMethodAsync pour invoquer la méthode .NET GetHelloMessage d’un composant :
<script>
window.sayHello1 = (dotNetHelper) => {
return dotNetHelper.invokeMethodAsync('GetHelloMessage');
};
</script>
Note
Pour des conseils généraux concernant l’emplacement JS et nos recommandations pour les applications de production, veuillez consulter la section Emplacement JavaScript dans les applications ASP.NET Core Blazor.
Dans l’exemple précédent, le nom de variable dotNetHelper est arbitraire et peut être remplacé par tout nom préféré.
Pour le composant suivant :
- Le composant possède une méthode .NET appelable via JS nommée
GetHelloMessage. - Lorsque le bouton
Trigger .NET instance methodest sélectionné, la fonction JSsayHello1est appelée avec le DotNetObjectReference. -
sayHello1:- Appelle
GetHelloMessageet reçoit le résultat du message. - Retourne le résultat du message à la méthode appelante
TriggerDotNetInstanceMethod.
- Appelle
- Le message retourné par
sayHello1dansresultest affiché à l’utilisateur. - Pour éviter une fuite de mémoire et permettre le ramassage de déchets, la référence d’objet .NET créée par DotNetObjectReference est supprimée dans la méthode
Dispose.
CallDotnet2.razor :
@page "/call-dotnet-2"
@implements IDisposable
@inject IJSRuntime JS
<PageTitle>Call .NET 2</PageTitle>
<h1>Call .NET Example 2</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
private DotNetObjectReference<CallDotnet2>? objRef;
protected override void OnInitialized() =>
objRef = DotNetObjectReference.Create(this);
public async Task TriggerDotNetInstanceMethod() =>
result = await JS.InvokeAsync<string>("sayHello1", objRef);
[JSInvokable]
public string GetHelloMessage() => $"Hello, {name}!";
public void Dispose() => objRef?.Dispose();
}
CallDotnet2.razor :
@page "/call-dotnet-2"
@implements IDisposable
@inject IJSRuntime JS
<PageTitle>Call .NET 2</PageTitle>
<h1>Call .NET Example 2</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
private DotNetObjectReference<CallDotnet2>? objRef;
protected override void OnInitialized() =>
objRef = DotNetObjectReference.Create(this);
public async Task TriggerDotNetInstanceMethod() =>
result = await JS.InvokeAsync<string>("sayHello1", objRef);
[JSInvokable]
public string GetHelloMessage() => $"Hello, {name}!";
public void Dispose() => objRef?.Dispose();
}
CallDotNetExample2.razor :
@page "/call-dotnet-example-2"
@implements IDisposable
@inject IJSRuntime JS
<h1>Call .NET Example 2</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
private DotNetObjectReference<CallDotNetExample2>? objRef;
protected override void OnInitialized()
{
objRef = DotNetObjectReference.Create(this);
}
public async Task TriggerDotNetInstanceMethod()
{
result = await JS.InvokeAsync<string>("sayHello1", objRef);
}
[JSInvokable]
public string GetHelloMessage() => $"Hello, {name}!";
public void Dispose()
{
objRef?.Dispose();
}
}
CallDotNetExample2.razor :
@page "/call-dotnet-example-2"
@implements IDisposable
@inject IJSRuntime JS
<h1>Call .NET Example 2</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
private DotNetObjectReference<CallDotNetExample2>? objRef;
protected override void OnInitialized()
{
objRef = DotNetObjectReference.Create(this);
}
public async Task TriggerDotNetInstanceMethod()
{
result = await JS.InvokeAsync<string>("sayHello1", objRef);
}
[JSInvokable]
public string GetHelloMessage() => $"Hello, {name}!";
public void Dispose()
{
objRef?.Dispose();
}
}
CallDotNetExample2.razor :
@page "/call-dotnet-example-2"
@implements IDisposable
@inject IJSRuntime JS
<h1>Call .NET Example 2</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string name;
private string result;
private DotNetObjectReference<CallDotNetExample2> objRef;
protected override void OnInitialized()
{
objRef = DotNetObjectReference.Create(this);
}
public async Task TriggerDotNetInstanceMethod()
{
result = await JS.InvokeAsync<string>("sayHello1", objRef);
}
[JSInvokable]
public string GetHelloMessage() => $"Hello, {name}!";
public void Dispose()
{
objRef?.Dispose();
}
}
CallDotNetExample2.razor :
@page "/call-dotnet-example-2"
@implements IDisposable
@inject IJSRuntime JS
<h1>Call .NET Example 2</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string name;
private string result;
private DotNetObjectReference<CallDotNetExample2> objRef;
protected override void OnInitialized()
{
objRef = DotNetObjectReference.Create(this);
}
public async Task TriggerDotNetInstanceMethod()
{
result = await JS.InvokeAsync<string>("sayHello1", objRef);
}
[JSInvokable]
public string GetHelloMessage() => $"Hello, {name}!";
public void Dispose()
{
objRef?.Dispose();
}
}
Dans l’exemple précédent, le nom de variable dotNetHelper est arbitraire et peut être remplacé par tout nom préféré.
Utilisez les indications suivantes pour transmettre des arguments à une méthode d’instance :
Ajoutez des paramètres à l’appel de la méthode .NET. Dans l’exemple suivant, un nom est transmis à la méthode. Ajoutez des paramètres supplémentaires à la liste si nécessaire.
<script>
window.sayHello2 = (dotNetHelper, name) => {
return dotNetHelper.invokeMethodAsync('GetHelloMessage', name);
};
</script>
Dans l’exemple précédent, le nom de variable dotNetHelper est arbitraire et peut être remplacé par tout nom préféré.
Fournissez la liste de paramètres à la méthode .NET.
CallDotnet3.razor :
@page "/call-dotnet-3"
@implements IDisposable
@inject IJSRuntime JS
<PageTitle>Call .NET 3</PageTitle>
<h1>Call .NET Example 3</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
private DotNetObjectReference<CallDotnet3>? objRef;
protected override void OnInitialized() =>
objRef = DotNetObjectReference.Create(this);
public async Task TriggerDotNetInstanceMethod() =>
result = await JS.InvokeAsync<string>("sayHello2", objRef, name);
[JSInvokable]
public string GetHelloMessage(string passedName) => $"Hello, {passedName}!";
public void Dispose() => objRef?.Dispose();
}
CallDotnet3.razor :
@page "/call-dotnet-3"
@implements IDisposable
@inject IJSRuntime JS
<PageTitle>Call .NET 3</PageTitle>
<h1>Call .NET Example 3</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
private DotNetObjectReference<CallDotnet3>? objRef;
protected override void OnInitialized() =>
objRef = DotNetObjectReference.Create(this);
public async Task TriggerDotNetInstanceMethod() =>
result = await JS.InvokeAsync<string>("sayHello2", objRef, name);
[JSInvokable]
public string GetHelloMessage(string passedName) => $"Hello, {passedName}!";
public void Dispose() => objRef?.Dispose();
}
CallDotNetExample3.razor :
@page "/call-dotnet-example-3"
@implements IDisposable
@inject IJSRuntime JS
<h1>Call .NET Example 3</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
private DotNetObjectReference<CallDotNetExample3>? objRef;
protected override void OnInitialized()
{
objRef = DotNetObjectReference.Create(this);
}
public async Task TriggerDotNetInstanceMethod()
{
result = await JS.InvokeAsync<string>("sayHello2", objRef, name);
}
[JSInvokable]
public string GetHelloMessage(string passedName) => $"Hello, {passedName}!";
public void Dispose()
{
objRef?.Dispose();
}
}
CallDotNetExample3.razor :
@page "/call-dotnet-example-3"
@implements IDisposable
@inject IJSRuntime JS
<h1>Call .NET Example 3</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
private DotNetObjectReference<CallDotNetExample3>? objRef;
protected override void OnInitialized()
{
objRef = DotNetObjectReference.Create(this);
}
public async Task TriggerDotNetInstanceMethod()
{
result = await JS.InvokeAsync<string>("sayHello2", objRef, name);
}
[JSInvokable]
public string GetHelloMessage(string passedName) => $"Hello, {passedName}!";
public void Dispose()
{
objRef?.Dispose();
}
}
CallDotNetExample3.razor :
@page "/call-dotnet-example-3"
@implements IDisposable
@inject IJSRuntime JS
<h1>Call .NET Example 3</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string name;
private string result;
private DotNetObjectReference<CallDotNetExample3> objRef;
protected override void OnInitialized()
{
objRef = DotNetObjectReference.Create(this);
}
public async Task TriggerDotNetInstanceMethod()
{
result = await JS.InvokeAsync<string>("sayHello2", objRef, name);
}
[JSInvokable]
public string GetHelloMessage(string passedName) => $"Hello, {passedName}!";
public void Dispose()
{
objRef?.Dispose();
}
}
CallDotNetExample3.razor :
@page "/call-dotnet-example-3"
@implements IDisposable
@inject IJSRuntime JS
<h1>Call .NET Example 3</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string name;
private string result;
private DotNetObjectReference<CallDotNetExample3> objRef;
protected override void OnInitialized()
{
objRef = DotNetObjectReference.Create(this);
}
public async Task TriggerDotNetInstanceMethod()
{
result = await JS.InvokeAsync<string>("sayHello2", objRef, name);
}
[JSInvokable]
public string GetHelloMessage(string passedName) => $"Hello, {passedName}!";
public void Dispose()
{
objRef?.Dispose();
}
}
Dans l’exemple précédent, le nom de variable dotNetHelper est arbitraire et peut être remplacé par tout nom préféré.
Transmettre un DotNetObjectReference à une classe contenant plusieurs fonctions JavaScript
L’exemple de cette section montre comment transmettre un DotNetObjectReference à une classe JavaScript (JS) contenant plusieurs fonctions.
Créez et transmettez un DotNetObjectReference à partir de la méthode de cycle de vie OnAfterRenderAsync à une classe JS afin que plusieurs fonctions puissent l’utiliser. Assurez-vous que le code .NET supprime le DotNetObjectReference, comme le montre l’exemple suivant.
Dans le composant suivant, les boutons Trigger JS function appellent des fonctions JS en définissant la propriété JSonclick, et non l’attribut de directive Blazor de @onclick.
CallDotNetExampleOneHelper.razor :
@page "/call-dotnet-example-one-helper"
@implements IAsyncDisposable
@inject IJSRuntime JS
<PageTitle>Call .NET Example</PageTitle>
<h1>Pass <code>DotNetObjectReference</code> to a JavaScript class</h1>
<p>
<label>
Message: <input @bind="name" />
</label>
</p>
<p>
<button id="sayHelloBtn">
Trigger JS function <code>sayHello</code>
</button>
</p>
<p>
<button id="welcomeVisitorBtn">
Trigger JS function <code>welcomeVisitor</code>
</button>
</p>
@code {
private IJSObjectReference? module;
private string? name;
private DotNetObjectReference<CallDotNetExampleOneHelper>? dotNetHelper;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
module = await JS.InvokeAsync<IJSObjectReference>("import",
"./Components/Pages/CallDotNetExampleOneHelper.razor.js");
dotNetHelper = DotNetObjectReference.Create(this);
await module.InvokeVoidAsync("GreetingHelpers.setDotNetHelper",
dotNetHelper);
await module.InvokeVoidAsync("addHandlers");
}
}
[JSInvokable]
public string GetHelloMessage() => $"Hello, {name}!";
[JSInvokable]
public string GetWelcomeMessage() => $"Welcome, {name}!";
async ValueTask IAsyncDisposable.DisposeAsync()
{
if (module is not null)
{
try
{
await module.DisposeAsync();
}
catch (JSDisconnectedException)
{
}
}
dotNetHelper?.Dispose();
}
}
Dans l'exemple précédent :
-
JSest une instance injectée de IJSRuntime. IJSRuntime est inscrit par le framework Blazor. - Le nom de variable
dotNetHelperest arbitraire et peut être remplacé par tout nom préféré. - Le composant doit supprimer explicitement le DotNetObjectReference pour permettre le garbage collection (GC) et éviter une fuite de mémoire.
-
JSDisconnectedException est capturé lors de la suppression du module si le circuit Blazor de SignalR est perdu. Si le code précédent est utilisé dans une application Blazor WebAssembly, il n’existe aucune connexion SignalR à perdre. Vous pouvez donc supprimer le bloc
try-catchet laisser la ligne qui supprime le module (await module.DisposeAsync();). Pour plus d’informations, consultez Interopérabilité JavaScript et ASP.NET Core Blazor (interopérabilité JS).
CallDotNetExampleOneHelper.razor.js :
export class GreetingHelpers {
static dotNetHelper;
static setDotNetHelper(value) {
GreetingHelpers.dotNetHelper = value;
}
static async sayHello() {
const msg =
await GreetingHelpers.dotNetHelper.invokeMethodAsync('GetHelloMessage');
alert(`Message from .NET: "${msg}"`);
}
static async welcomeVisitor() {
const msg =
await GreetingHelpers.dotNetHelper.invokeMethodAsync('GetWelcomeMessage');
alert(`Message from .NET: "${msg}"`);
}
}
export function addHandlers() {
const sayHelloBtn = document.getElementById("sayHelloBtn");
sayHelloBtn.addEventListener("click", GreetingHelpers.sayHello);
const welcomeVisitorBtn = document.getElementById("welcomeVisitorBtn");
welcomeVisitorBtn.addEventListener("click", GreetingHelpers.welcomeVisitor);
}
Dans l’exemple précédent, le nom de variable dotNetHelper est arbitraire et peut être remplacé par tout nom préféré.
@page "/call-dotnet-example-one-helper"
@implements IDisposable
@inject IJSRuntime JS
<h1>Pass <code>DotNetObjectReference</code> to a JavaScript class</h1>
<p>
<label>
Message: <input @bind="name" />
</label>
</p>
<p>
<button onclick="GreetingHelpers.sayHello()">
Trigger JS function <code>sayHello</code>
</button>
</p>
<p>
<button onclick="GreetingHelpers.welcomeVisitor()">
Trigger JS function <code>welcomeVisitor</code>
</button>
</p>
@code {
private string? name;
private DotNetObjectReference<CallDotNetExampleOneHelper>? dotNetHelper;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
dotNetHelper = DotNetObjectReference.Create(this);
await JS.InvokeVoidAsync("GreetingHelpers.setDotNetHelper",
dotNetHelper);
}
}
[JSInvokable]
public string GetHelloMessage() => $"Hello, {name}!";
[JSInvokable]
public string GetWelcomeMessage() => $"Welcome, {name}!";
public void Dispose()
{
dotNetHelper?.Dispose();
}
}
Dans l'exemple précédent :
-
JSest une instance injectée de IJSRuntime. IJSRuntime est inscrit par le framework Blazor. - Le nom de variable
dotNetHelperest arbitraire et peut être remplacé par tout nom préféré. - Le composant doit supprimer explicitement le DotNetObjectReference pour permettre le garbage collection (GC) et éviter une fuite de mémoire.
<script>
class GreetingHelpers {
static dotNetHelper;
static setDotNetHelper(value) {
GreetingHelpers.dotNetHelper = value;
}
static async sayHello() {
const msg =
await GreetingHelpers.dotNetHelper.invokeMethodAsync('GetHelloMessage');
alert(`Message from .NET: "${msg}"`);
}
static async welcomeVisitor() {
const msg =
await GreetingHelpers.dotNetHelper.invokeMethodAsync('GetWelcomeMessage');
alert(`Message from .NET: "${msg}"`);
}
}
window.GreetingHelpers = GreetingHelpers;
</script>
Dans l'exemple précédent :
- La classe
GreetingHelpersest ajoutée à l’objetwindowpour définir globalement la classe, ce qui permet à Blazor de la localiser pour l’interopérabilité JS. - Le nom de variable
dotNetHelperest arbitraire et peut être remplacé par tout nom préféré.
Note
Pour des conseils généraux concernant l’emplacement JS et nos recommandations pour les applications de production, veuillez consulter la section Emplacement JavaScript dans les applications ASP.NET Core Blazor.
Appeler des méthodes de classe générique .NET
Les fonctions JavaScript (JS) peuvent appeler des méthodes de classe générique .NET, où une fonction JS appelle une méthode .NET d’une classe générique.
Dans la classe générique suivante (GenericType<TValue>) :
- La classe comporte un seul paramètre de type (
TValue) avec une seule propriété génériqueValue. - La classe comporte deux méthodes non génériques marquées avec l’attribut
[JSInvokable], chacune avec un paramètre de type générique nomménewValue:-
Updatemet à jour de manière synchrone la valeur deValuedepuisnewValue. -
UpdateAsyncmet à jour de manière asynchrone la valeur deValuedepuisnewValueaprès avoir créé une tâche awaitable avec Task.Yield qui restitue de manière asynchrone le contrôle au contexte courant lorsqu’elle est attendue.
-
- Chacune des méthodes de la classe écrit le type de
TValueet la valeur deValuedans la console. L’écriture dans la console est uniquement à des fins de démonstration. Les applications de production évitent généralement l’écriture dans la console au profit du framework de journalisation de l’application. Pour plus d’informations, consultez ASP.NET Core Blazor journalisation et journalisation dans .NET et ASP.NET Core.
Note
Les types et méthodes génériques ouverts ne spécifient pas de types pour les espaces réservés de type. À l’inverse, les génériques fermés fournissent des types pour tous les espaces réservés de type. Les exemples de cette section démontrent des génériques fermés, mais l’appel de JS interop avec des génériques ouverts est pris en charge. L’utilisation de génériques ouverts n’est pas prise en charge pour les appels de méthodes .NET statiques, qui ont été décrits plus tôt dans cette rubrique.
Si vous souhaitez en savoir plus, consultez les articles suivants :
- Classes et méthodes génériques (documentation C#)
- Classes génériques (guide de programmation C#)
- Génériques dans .NET (documentation .NET)
GenericType.cs :
using Microsoft.JSInterop;
public class GenericType<TValue>
{
public TValue? Value { get; set; }
[JSInvokable]
public void Update(TValue newValue)
{
Value = newValue;
Console.WriteLine($"Update: GenericType<{typeof(TValue)}>: {Value}");
}
[JSInvokable]
public async Task UpdateAsync(TValue newValue)
{
await Task.Yield();
Value = newValue;
Console.WriteLine($"UpdateAsync: GenericType<{typeof(TValue)}>: {Value}");
}
}
Dans la fonction invokeMethodsAsync suivante :
- Les méthodes
UpdateetUpdateAsyncde la classe générique sont appelées avec des arguments représentant des chaînes de caractères et des nombres. - Les composants côté client prennent en charge l’appel synchrone des méthodes .NET avec
invokeMethod.syncInteropreçoit une valeur booléenne indiquant si l’interopérabilité JS s’effectue côté client. LorsquesyncInteropvauttrue,invokeMethodest appelé en toute sécurité. Si la valeur desyncInteropestfalse, seule la fonction asynchroneinvokeMethodAsyncest appelée, car l’interopérabilité JS s’exécute dans un composant côté serveur. - À des fins de démonstration, l’appel de la fonction DotNetObjectReference (
invokeMethodouinvokeMethodAsync), la méthode .NET appelée (UpdateouUpdateAsync) et l’argument sont écrits dans la console. Les arguments utilisent un nombre aléatoire pour permettre de faire correspondre l’appel de la fonction JS avec l’appel de la méthode .NET (également écrit dans la console côté .NET). Le code de production n’écrit généralement pas dans la console, que ce soit côté client ou côté serveur. Les applications de production s’appuient généralement sur le framework de journalisation de l’application. Pour plus d’informations, consultez ASP.NET Core Blazor journalisation et journalisation dans .NET et ASP.NET Core.
<script>
const randomInt = () => Math.floor(Math.random() * 99999);
window.invokeMethodsAsync = async (syncInterop, dotNetHelper1, dotNetHelper2) => {
var n = randomInt();
console.log(`JS: invokeMethodAsync:Update('string ${n}')`);
await dotNetHelper1.invokeMethodAsync('Update', `string ${n}`);
n = randomInt();
console.log(`JS: invokeMethodAsync:UpdateAsync('string ${n}')`);
await dotNetHelper1.invokeMethodAsync('UpdateAsync', `string ${n}`);
if (syncInterop) {
n = randomInt();
console.log(`JS: invokeMethod:Update('string ${n}')`);
dotNetHelper1.invokeMethod('Update', `string ${n}`);
}
n = randomInt();
console.log(`JS: invokeMethodAsync:Update(${n})`);
await dotNetHelper2.invokeMethodAsync('Update', n);
n = randomInt();
console.log(`JS: invokeMethodAsync:UpdateAsync(${n})`);
await dotNetHelper2.invokeMethodAsync('UpdateAsync', n);
if (syncInterop) {
n = randomInt();
console.log(`JS: invokeMethod:Update(${n})`);
dotNetHelper2.invokeMethod('Update', n);
}
};
</script>
Note
Pour des conseils généraux concernant l’emplacement JS et nos recommandations pour les applications de production, veuillez consulter la section Emplacement JavaScript dans les applications ASP.NET Core Blazor.
Dans le composant GenericsExample suivant :
- La fonction JS
invokeMethodsAsyncest appelée lorsque le boutonInvoke Interopest sélectionné. - Une paire de types DotNetObjectReference est créée et transmise à la fonction JS pour des instances de
GenericTypeen tant questringetint.
GenericsExample.razor :
@page "/generics-example"
@implements IDisposable
@inject IJSRuntime JS
<p>
<button @onclick="InvokeInterop">Invoke Interop</button>
</p>
<ul>
<li>genericType1: @genericType1?.Value</li>
<li>genericType2: @genericType2?.Value</li>
</ul>
@code {
private GenericType<string> genericType1 = new() { Value = "string 0" };
private GenericType<int> genericType2 = new() { Value = 0 };
private DotNetObjectReference<GenericType<string>>? objRef1;
private DotNetObjectReference<GenericType<int>>? objRef2;
protected override void OnInitialized()
{
objRef1 = DotNetObjectReference.Create(genericType1);
objRef2 = DotNetObjectReference.Create(genericType2);
}
public async Task InvokeInterop()
{
var syncInterop = OperatingSystem.IsBrowser();
await JS.InvokeVoidAsync(
"invokeMethodsAsync", syncInterop, objRef1, objRef2);
}
public void Dispose()
{
objRef1?.Dispose();
objRef2?.Dispose();
}
}
@page "/generics-example"
@implements IDisposable
@inject IJSRuntime JS
<p>
<button @onclick="InvokeInterop">Invoke Interop</button>
</p>
<ul>
<li>genericType1: @genericType1?.Value</li>
<li>genericType2: @genericType2?.Value</li>
</ul>
@code {
private GenericType<string> genericType1 = new() { Value = "string 0" };
private GenericType<int> genericType2 = new() { Value = 0 };
private DotNetObjectReference<GenericType<string>>? objRef1;
private DotNetObjectReference<GenericType<int>>? objRef2;
protected override void OnInitialized()
{
objRef1 = DotNetObjectReference.Create(genericType1);
objRef2 = DotNetObjectReference.Create(genericType2);
}
public async Task InvokeInterop()
{
var syncInterop = OperatingSystem.IsBrowser();
await JS.InvokeVoidAsync(
"invokeMethodsAsync", syncInterop, objRef1, objRef2);
}
public void Dispose()
{
objRef1?.Dispose();
objRef2?.Dispose();
}
}
Dans l’exemple précédent, JS est une instance injectée de IJSRuntime.
IJSRuntime est inscrit par le framework Blazor.
L’exemple suivant montre une sortie typique de l’exemple précédent lorsque le bouton Invoke Interop est sélectionné dans un composant côté client :
JS : invokeMethodAsync\:Update('string 37802')
.NET : Update : GenericType<System.String> : string 37802
JS: invokeMethodAsync :UpdateAsync('string 53051')
JS: invokeMethod :Update('string 26784')
.NET : Mise à jour : GenericType<System.String> : string 26784
JS: invokeMethodAsync :Update(14107)
.NET : Mise à jour : GenericType<System.Int32> : 14107
JS: invokeMethodAsync :UpdateAsync(48995)
JS: invokeMethod :Update(12872)
.NET : Mise à jour : GenericType<System.Int32> : 12872
.NET : UpdateAsync : GenericType<System.String> : string 53051
.NET : UpdateAsync : GenericType<System.Int32> : 48995
Si l’exemple précédent est implémenté dans un composant côté serveur, les appels synchrones avec invokeMethod sont évités. Pour les composants côté serveur, nous recommandons la fonction asynchrone (invokeMethodAsync) plutôt que la version synchrone (invokeMethod).
Sortie typique d’un composant côté serveur :
JS : invokeMethodAsync\:Update('string 34809')
.NET : Mise à jour : GenericType<System.String> : string 34809
JS: invokeMethodAsync :UpdateAsync('string 93059')
JS: invokeMethodAsync :Update(41997)
.NET : Mise à jour : GenericType<System.Int32> : 41997
JS: invokeMethodAsync :UpdateAsync(24652)
.NET : UpdateAsync : GenericType<System.String> : string 93059
.NET : UpdateAsync : GenericType<System.Int32> : 24652
Les exemples de sortie précédents montrent que les méthodes asynchrones s’exécutent et se terminent dans un ordre arbitraire selon plusieurs facteurs, notamment l’ordonnancement des threads et la vitesse d’exécution des méthodes. Il n’est pas possible de prévoir de manière fiable l’ordre d’exécution des appels de méthodes asynchrones.
Exemples d’instance de classe
La fonction sayHello1JS suivante :
- Appelle la méthode .NET
GetHelloMessagesur le DotNetObjectReference transmis. - Retourne le message de
GetHelloMessageà l’appelantsayHello1.
<script>
window.sayHello1 = (dotNetHelper) => {
return dotNetHelper.invokeMethodAsync('GetHelloMessage');
};
</script>
Note
Pour des conseils généraux concernant l’emplacement JS et nos recommandations pour les applications de production, veuillez consulter la section Emplacement JavaScript dans les applications ASP.NET Core Blazor.
Dans l’exemple précédent, le nom de variable dotNetHelper est arbitraire et peut être remplacé par tout nom préféré.
La classe HelloHelper suivante possède une méthode .NET appelable via JS nommée GetHelloMessage. Lors de la création de HelloHelper, le nom dans la propriété Name est utilisé pour retourner un message depuis GetHelloMessage.
HelloHelper.cs :
using Microsoft.JSInterop;
namespace BlazorSample;
public class HelloHelper(string? name)
{
public string? Name { get; set; } = name ?? "No Name";
[JSInvokable]
public string GetHelloMessage() => $"Hello, {Name}!";
}
using Microsoft.JSInterop;
namespace BlazorSample;
public class HelloHelper(string? name)
{
public string? Name { get; set; } = name ?? "No Name";
[JSInvokable]
public string GetHelloMessage() => $"Hello, {Name}!";
}
using Microsoft.JSInterop;
public class HelloHelper
{
public HelloHelper(string? name)
{
Name = name ?? "No Name";
}
public string? Name { get; set; }
[JSInvokable]
public string GetHelloMessage() => $"Hello, {Name}!";
}
using Microsoft.JSInterop;
public class HelloHelper
{
public HelloHelper(string? name)
{
Name = name ?? "No Name";
}
public string? Name { get; set; }
[JSInvokable]
public string GetHelloMessage() => $"Hello, {Name}!";
}
using Microsoft.JSInterop;
public class HelloHelper
{
public HelloHelper(string name)
{
Name = name;
}
public string Name { get; set; }
[JSInvokable]
public string GetHelloMessage() => $"Hello, {Name}!";
}
using Microsoft.JSInterop;
public class HelloHelper
{
public HelloHelper(string name)
{
Name = name;
}
public string Name { get; set; }
[JSInvokable]
public string GetHelloMessage() => $"Hello, {Name}!";
}
La méthode CallHelloHelperGetHelloMessage dans la classe JsInteropClasses3 suivante appelle la fonction JSsayHello1 avec une nouvelle instance de HelloHelper.
JsInteropClasses3.cs :
using Microsoft.JSInterop;
namespace BlazorSample;
public class JsInteropClasses3(IJSRuntime js)
{
private readonly IJSRuntime js = js;
public async ValueTask<string> CallHelloHelperGetHelloMessage(string? name)
{
using var objRef = DotNetObjectReference.Create(new HelloHelper(name));
return await js.InvokeAsync<string>("sayHello1", objRef);
}
}
using Microsoft.JSInterop;
namespace BlazorSample;
public class JsInteropClasses3(IJSRuntime js)
{
private readonly IJSRuntime js = js;
public async ValueTask<string> CallHelloHelperGetHelloMessage(string? name)
{
using var objRef = DotNetObjectReference.Create(new HelloHelper(name));
return await js.InvokeAsync<string>("sayHello1", objRef);
}
}
using Microsoft.JSInterop;
public class JsInteropClasses3
{
private readonly IJSRuntime js;
public JsInteropClasses3(IJSRuntime js)
{
this.js = js;
}
public async ValueTask<string> CallHelloHelperGetHelloMessage(string? name)
{
using var objRef = DotNetObjectReference.Create(new HelloHelper(name));
return await js.InvokeAsync<string>("sayHello1", objRef);
}
}
using Microsoft.JSInterop;
public class JsInteropClasses3
{
private readonly IJSRuntime js;
public JsInteropClasses3(IJSRuntime js)
{
this.js = js;
}
public async ValueTask<string> CallHelloHelperGetHelloMessage(string? name)
{
using var objRef = DotNetObjectReference.Create(new HelloHelper(name));
return await js.InvokeAsync<string>("sayHello1", objRef);
}
}
using System.Threading.Tasks;
using Microsoft.JSInterop;
public class JsInteropClasses3
{
private readonly IJSRuntime js;
public JsInteropClasses3(IJSRuntime js)
{
this.js = js;
}
public async ValueTask<string> CallHelloHelperGetHelloMessage(string name)
{
using var objRef = DotNetObjectReference.Create(new HelloHelper(name));
return await js.InvokeAsync<string>("sayHello1", objRef);
}
}
using System.Threading.Tasks;
using Microsoft.JSInterop;
public class JsInteropClasses3
{
private readonly IJSRuntime js;
public JsInteropClasses3(IJSRuntime js)
{
this.js = js;
}
public async ValueTask<string> CallHelloHelperGetHelloMessage(string name)
{
using var objRef = DotNetObjectReference.Create(new HelloHelper(name));
return await js.InvokeAsync<string>("sayHello1", objRef);
}
}
Pour éviter une fuite de mémoire et permettre le garbage collection, la référence d’objet .NET créée par DotNetObjectReference est supprimée lorsque la référence sort de la portée à l’aide de la syntaxe using var.
Lorsque le bouton Trigger .NET instance method est sélectionné dans le composant suivant, JsInteropClasses3.CallHelloHelperGetHelloMessage est appelé avec la valeur de name.
CallDotnet4.razor :
@page "/call-dotnet-4"
@inject IJSRuntime JS
<PageTitle>Call .NET 4</PageTitle>
<h1>Call .NET Example 4</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
private JsInteropClasses3? jsInteropClasses;
protected override void OnInitialized() =>
jsInteropClasses = new JsInteropClasses3(JS);
private async Task TriggerDotNetInstanceMethod()
{
if (jsInteropClasses is not null)
{
result = await jsInteropClasses.CallHelloHelperGetHelloMessage(name);
}
}
}
CallDotnet4.razor :
@page "/call-dotnet-4"
@inject IJSRuntime JS
<PageTitle>Call .NET 4</PageTitle>
<h1>Call .NET Example 4</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
private JsInteropClasses3? jsInteropClasses;
protected override void OnInitialized() =>
jsInteropClasses = new JsInteropClasses3(JS);
private async Task TriggerDotNetInstanceMethod()
{
if (jsInteropClasses is not null)
{
result = await jsInteropClasses.CallHelloHelperGetHelloMessage(name);
}
}
}
CallDotNetExample4.razor :
@page "/call-dotnet-example-4"
@inject IJSRuntime JS
<h1>Call .NET Example 4</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
private JsInteropClasses3? jsInteropClasses;
protected override void OnInitialized()
{
jsInteropClasses = new JsInteropClasses3(JS);
}
private async Task TriggerDotNetInstanceMethod()
{
if (jsInteropClasses is not null)
{
result = await jsInteropClasses.CallHelloHelperGetHelloMessage(name);
}
}
}
CallDotNetExample4.razor :
@page "/call-dotnet-example-4"
@inject IJSRuntime JS
<h1>Call .NET Example 4</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
private JsInteropClasses3? jsInteropClasses;
protected override void OnInitialized()
{
jsInteropClasses = new JsInteropClasses3(JS);
}
private async Task TriggerDotNetInstanceMethod()
{
if (jsInteropClasses is not null)
{
result = await jsInteropClasses.CallHelloHelperGetHelloMessage(name);
}
}
}
CallDotNetExample4.razor :
@page "/call-dotnet-example-4"
@inject IJSRuntime JS
<h1>Call .NET Example 4</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string name;
private string result;
private JsInteropClasses3 jsInteropClasses;
protected override void OnInitialized()
{
jsInteropClasses = new JsInteropClasses3(JS);
}
private async Task TriggerDotNetInstanceMethod()
{
result = await jsInteropClasses.CallHelloHelperGetHelloMessage(name);
}
}
CallDotNetExample4.razor :
@page "/call-dotnet-example-4"
@inject IJSRuntime JS
<h1>Call .NET Example 4</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string name;
private string result;
private JsInteropClasses3 jsInteropClasses;
protected override void OnInitialized()
{
jsInteropClasses = new JsInteropClasses3(JS);
}
private async Task TriggerDotNetInstanceMethod()
{
result = await jsInteropClasses.CallHelloHelperGetHelloMessage(name);
}
}
L’image suivante montre le composant rendu avec le nom Amy Pond dans le champ Name. Après sélection du bouton, Hello, Amy Pond! est affiché dans l’interface utilisateur :
Le modèle précédent montré dans la classe JsInteropClasses3 peut également être entièrement implémenté dans un composant.
CallDotnet5.razor :
@page "/call-dotnet-5"
@inject IJSRuntime JS
<PageTitle>Call .NET 5</PageTitle>
<h1>Call .NET Example 5</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
public async Task TriggerDotNetInstanceMethod()
{
using var objRef = DotNetObjectReference.Create(new HelloHelper(name));
result = await JS.InvokeAsync<string>("sayHello1", objRef);
}
}
CallDotnet5.razor :
@page "/call-dotnet-5"
@inject IJSRuntime JS
<PageTitle>Call .NET 5</PageTitle>
<h1>Call .NET Example 5</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
public async Task TriggerDotNetInstanceMethod()
{
using var objRef = DotNetObjectReference.Create(new HelloHelper(name));
result = await JS.InvokeAsync<string>("sayHello1", objRef);
}
}
CallDotNetExample5.razor :
@page "/call-dotnet-example-5"
@inject IJSRuntime JS
<h1>Call .NET Example 5</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
public async Task TriggerDotNetInstanceMethod()
{
using var objRef = DotNetObjectReference.Create(new HelloHelper(name));
result = await JS.InvokeAsync<string>("sayHello1", objRef);
}
}
CallDotNetExample5.razor :
@page "/call-dotnet-example-5"
@inject IJSRuntime JS
<h1>Call .NET Example 5</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
public async Task TriggerDotNetInstanceMethod()
{
using var objRef = DotNetObjectReference.Create(new HelloHelper(name));
result = await JS.InvokeAsync<string>("sayHello1", objRef);
}
}
CallDotNetExample5.razor :
@page "/call-dotnet-example-5"
@inject IJSRuntime JS
<h1>Call .NET Example 5</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string name;
private string result;
public async Task TriggerDotNetInstanceMethod()
{
using var objRef = DotNetObjectReference.Create(new HelloHelper(name));
result = await JS.InvokeAsync<string>("sayHello1", objRef);
}
}
CallDotNetExample5.razor :
@page "/call-dotnet-example-5"
@inject IJSRuntime JS
<h1>Call .NET Example 5</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string name;
private string result;
public async Task TriggerDotNetInstanceMethod()
{
using var objRef = DotNetObjectReference.Create(new HelloHelper(name));
result = await JS.InvokeAsync<string>("sayHello1", objRef);
}
}
Pour éviter une fuite de mémoire et permettre le garbage collection, la référence d’objet .NET créée par DotNetObjectReference est supprimée lorsque la référence sort de la portée à l’aide de la syntaxe using var.
La sortie affichée par le composant est Hello, Amy Pond! lorsque le nom Amy Pond est saisi dans le champ name.
Dans le composant précédent, la référence d’objet .NET est supprimée. Si une classe ou un composant ne supprime pas le DotNetObjectReference, supprimez-le côté client en appelant dispose sur le DotNetObjectReference transmis :
window.{JS FUNCTION NAME} = (dotNetHelper) => {
dotNetHelper.invokeMethodAsync('{.NET METHOD ID}');
dotNetHelper.dispose();
}
Dans l'exemple précédent :
- L’espace réservé
{JS FUNCTION NAME}correspond au nom de la fonction JS. - Le nom de variable
dotNetHelperest arbitraire et peut être remplacé par tout nom préféré. - L’espace réservé
{.NET METHOD ID}correspond à l’identifiant de la méthode .NET.
Classe d’assistance pour méthode .NET d’instance de composant
Une classe d’assistance peut appeler une méthode .NET d’instance comme un Action. Les classes d’assistance sont utiles dans des scénarios où l’utilisation de méthodes .NET statiques n’est pas applicable :
- Lorsque plusieurs composants du même type sont rendus sur la même page.
- Dans les applications côté serveur avec plusieurs utilisateurs utilisant simultanément le même composant.
Dans l’exemple suivant :
- Le composant contient plusieurs composants
ListItem1. - Chaque composant
ListItem1se compose d’un message et d’un bouton. - Lorsqu’un bouton d’un composant
ListItem1est sélectionné, la méthodeListItem1de ceUpdateMessagemodifie le texte de l’élément de liste et masque le bouton.
La classe MessageUpdateInvokeHelper suivante conserve une méthode .NET appelable via JS, UpdateMessageCaller, pour appeler le Action spécifié lors de l’instanciation de la classe.
MessageUpdateInvokeHelper.cs :
using Microsoft.JSInterop;
namespace BlazorSample;
public class MessageUpdateInvokeHelper(Action action)
{
private readonly Action action = action;
[JSInvokable]
public void UpdateMessageCaller() => action.Invoke();
}
using Microsoft.JSInterop;
namespace BlazorSample;
public class MessageUpdateInvokeHelper(Action action)
{
private readonly Action action = action;
[JSInvokable]
public void UpdateMessageCaller() => action.Invoke();
}
using Microsoft.JSInterop;
public class MessageUpdateInvokeHelper
{
private Action action;
public MessageUpdateInvokeHelper(Action action)
{
this.action = action;
}
[JSInvokable]
public void UpdateMessageCaller()
{
action.Invoke();
}
}
using Microsoft.JSInterop;
public class MessageUpdateInvokeHelper
{
private Action action;
public MessageUpdateInvokeHelper(Action action)
{
this.action = action;
}
[JSInvokable]
public void UpdateMessageCaller()
{
action.Invoke();
}
}
using System;
using Microsoft.JSInterop;
public class MessageUpdateInvokeHelper
{
private Action action;
public MessageUpdateInvokeHelper(Action action)
{
this.action = action;
}
[JSInvokable]
public void UpdateMessageCaller()
{
action.Invoke();
}
}
using System;
using Microsoft.JSInterop;
public class MessageUpdateInvokeHelper
{
private Action action;
public MessageUpdateInvokeHelper(Action action)
{
this.action = action;
}
[JSInvokable]
public void UpdateMessageCaller()
{
action.Invoke();
}
}
La fonction updateMessageCallerJS suivante appelle la méthode .NET UpdateMessageCaller.
<script>
window.updateMessageCaller = (dotNetHelper) => {
dotNetHelper.invokeMethodAsync('UpdateMessageCaller');
dotNetHelper.dispose();
}
</script>
Note
Pour des conseils généraux concernant l’emplacement JS et nos recommandations pour les applications de production, veuillez consulter la section Emplacement JavaScript dans les applications ASP.NET Core Blazor.
Dans l’exemple précédent, le nom de variable dotNetHelper est arbitraire et peut être remplacé par tout nom préféré.
Le composant ListItem1 suivant est un composant partagé qui peut être utilisé autant de fois que nécessaire dans un composant parent et crée des éléments de liste (<li>...</li>) pour une liste HTML (<ul>...</ul> ou <ol>...</ol>). Chaque instance du composant ListItem1 crée une instance de MessageUpdateInvokeHelper avec un Action défini sur sa méthode UpdateMessage.
Lorsque le bouton ListItem1 d’un composant InteropCall est sélectionné, updateMessageCaller est appelé avec un DotNetObjectReference créé pour l’instance MessageUpdateInvokeHelper. Cela permet au framework d’appeler UpdateMessageCaller sur l’instance ListItem1 du MessageUpdateInvokeHelper concerné. Le DotNetObjectReference transmis est supprimé dans JS (dotNetHelper.dispose()).
ListItem1.razor :
@inject IJSRuntime JS
<li>
@message
<button @onclick="InteropCall" style="display:@display">InteropCall</button>
</li>
@code {
private string message = "Select one of these list item buttons.";
private string display = "inline-block";
private MessageUpdateInvokeHelper? messageUpdateInvokeHelper;
protected override void OnInitialized()
{
messageUpdateInvokeHelper = new MessageUpdateInvokeHelper(UpdateMessage);
}
protected async Task InteropCall()
{
if (messageUpdateInvokeHelper is not null)
{
await JS.InvokeVoidAsync("updateMessageCaller",
DotNetObjectReference.Create(messageUpdateInvokeHelper));
}
}
private void UpdateMessage()
{
message = "UpdateMessage Called!";
display = "none";
StateHasChanged();
}
}
@inject IJSRuntime JS
<li>
@message
<button @onclick="InteropCall" style="display:@display">InteropCall</button>
</li>
@code {
private string message = "Select one of these list item buttons.";
private string display = "inline-block";
private MessageUpdateInvokeHelper? messageUpdateInvokeHelper;
protected override void OnInitialized()
{
messageUpdateInvokeHelper = new MessageUpdateInvokeHelper(UpdateMessage);
}
protected async Task InteropCall()
{
if (messageUpdateInvokeHelper is not null)
{
await JS.InvokeVoidAsync("updateMessageCaller",
DotNetObjectReference.Create(messageUpdateInvokeHelper));
}
}
private void UpdateMessage()
{
message = "UpdateMessage Called!";
display = "none";
StateHasChanged();
}
}
@inject IJSRuntime JS
<li>
@message
<button @onclick="InteropCall" style="display:@display">InteropCall</button>
</li>
@code {
private string message = "Select one of these list item buttons.";
private string display = "inline-block";
private MessageUpdateInvokeHelper? messageUpdateInvokeHelper;
protected override void OnInitialized()
{
messageUpdateInvokeHelper = new MessageUpdateInvokeHelper(UpdateMessage);
}
protected async Task InteropCall()
{
if (messageUpdateInvokeHelper is not null)
{
await JS.InvokeVoidAsync("updateMessageCaller",
DotNetObjectReference.Create(messageUpdateInvokeHelper));
}
}
private void UpdateMessage()
{
message = "UpdateMessage Called!";
display = "none";
StateHasChanged();
}
}
@inject IJSRuntime JS
<li>
@message
<button @onclick="InteropCall" style="display:@display">InteropCall</button>
</li>
@code {
private string message = "Select one of these list item buttons.";
private string display = "inline-block";
private MessageUpdateInvokeHelper? messageUpdateInvokeHelper;
protected override void OnInitialized()
{
messageUpdateInvokeHelper = new MessageUpdateInvokeHelper(UpdateMessage);
}
protected async Task InteropCall()
{
if (messageUpdateInvokeHelper is not null)
{
await JS.InvokeVoidAsync("updateMessageCaller",
DotNetObjectReference.Create(messageUpdateInvokeHelper));
}
}
private void UpdateMessage()
{
message = "UpdateMessage Called!";
display = "none";
StateHasChanged();
}
}
@inject IJSRuntime JS
<li>
@message
<button @onclick="InteropCall" style="display:@display">InteropCall</button>
</li>
@code {
private string message = "Select one of these list item buttons.";
private string display = "inline-block";
private MessageUpdateInvokeHelper messageUpdateInvokeHelper;
protected override void OnInitialized()
{
messageUpdateInvokeHelper = new MessageUpdateInvokeHelper(UpdateMessage);
}
protected async Task InteropCall()
{
await JS.InvokeVoidAsync("updateMessageCaller",
DotNetObjectReference.Create(messageUpdateInvokeHelper));
}
private void UpdateMessage()
{
message = "UpdateMessage Called!";
display = "none";
StateHasChanged();
}
}
@inject IJSRuntime JS
<li>
@message
<button @onclick="InteropCall" style="display:@display">InteropCall</button>
</li>
@code {
private string message = "Select one of these list item buttons.";
private string display = "inline-block";
private MessageUpdateInvokeHelper messageUpdateInvokeHelper;
protected override void OnInitialized()
{
messageUpdateInvokeHelper = new MessageUpdateInvokeHelper(UpdateMessage);
}
protected async Task InteropCall()
{
await JS.InvokeVoidAsync("updateMessageCaller",
DotNetObjectReference.Create(messageUpdateInvokeHelper));
}
private void UpdateMessage()
{
message = "UpdateMessage Called!";
display = "none";
StateHasChanged();
}
}
StateHasChanged est appelé pour mettre à jour l’interface utilisateur lorsque message est défini dans UpdateMessage. Si StateHasChanged n’est pas appelé, Blazor ne peut pas savoir que l’interface utilisateur doit être mise à jour lorsque Action est invoqué.
Le composant parent suivant inclut quatre éléments de liste, chacun étant une instance du composant ListItem1.
CallDotnet6.razor :
@page "/call-dotnet-6"
<PageTitle>Call .NET 6</PageTitle>
<h1>Call .NET Example 6</h1>
<ul>
<ListItem1 />
<ListItem1 />
<ListItem1 />
<ListItem1 />
</ul>
CallDotnet6.razor :
@page "/call-dotnet-6"
<PageTitle>Call .NET 6</PageTitle>
<h1>Call .NET Example 6</h1>
<ul>
<ListItem1 />
<ListItem1 />
<ListItem1 />
<ListItem1 />
</ul>
CallDotNetExample6.razor :
@page "/call-dotnet-example-6"
<h1>Call .NET Example 6</h1>
<ul>
<ListItem1 />
<ListItem1 />
<ListItem1 />
<ListItem1 />
</ul>
CallDotNetExample6.razor :
@page "/call-dotnet-example-6"
<h1>Call .NET Example 6</h1>
<ul>
<ListItem1 />
<ListItem1 />
<ListItem1 />
<ListItem1 />
</ul>
CallDotNetExample6.razor :
@page "/call-dotnet-example-6"
<h1>Call .NET Example 6</h1>
<ul>
<ListItem1 />
<ListItem1 />
<ListItem1 />
<ListItem1 />
</ul>
CallDotNetExample6.razor :
@page "/call-dotnet-example-6"
<h1>Call .NET Example 6</h1>
<ul>
<ListItem1 />
<ListItem1 />
<ListItem1 />
<ListItem1 />
</ul>
L’image suivante montre le composant parent rendu après sélection du deuxième bouton InteropCall :
- Le deuxième composant
ListItem1a affiché le messageUpdateMessage Called!. - Le bouton
InteropCalldu deuxième composantListItem1n’est pas visible, car la propriété CSSdisplaydu bouton est définie surnone.
Méthode .NET d’instance de composant appelée depuis DotNetObjectReference affecté à une propriété d’élément
L’affectation d’un DotNetObjectReference à une propriété d’un élément HTML permet d’appeler des méthodes .NET sur une instance de composant :
- Une référence d’élément est capturée (ElementReference).
- Dans la méthode
OnAfterRender{Async}du composant, une fonction JavaScript (JS) est appelée avec la référence de l’élément et l’instance du composant en tant que DotNetObjectReference. La fonction JS attache le DotNetObjectReference à l’élément dans une propriété. - Lorsqu’un événement d’élément est invoqué dans JS (par exemple,
onclick), le DotNetObjectReference attaché à l’élément est utilisé pour appeler une méthode .NET.
Comme pour l’approche décrite dans la section Classe d’assistance pour méthode .NET d’instance de composant, cette méthode est utile dans les cas où les méthodes .NET statiques ne conviennent pas :
- Lorsque plusieurs composants du même type sont rendus sur la même page.
- Dans les applications côté serveur avec plusieurs utilisateurs utilisant simultanément le même composant.
- La méthode .NET est appelée à partir d’un événement JS (par exemple,
onclick), et non d’un événement Blazor (par exemple,@onclick).
Dans l’exemple suivant :
- Le composant contient plusieurs composants
ListItem2, qui est un composant partagé. - Chaque composant
ListItem2est composé d’un message d’élément de liste<span>et d’un second<span>avec une propriété CSSdisplaydéfinie surinline-blockpour l’affichage. - Lorsqu’un élément de liste d’un composant
ListItem2est sélectionné, la méthodeListItem2de ceUpdateMessagemodifie le texte de l’élément de liste dans le premier<span>et masque le second<span>en définissant sa propriétédisplaysurnone.
La fonction assignDotNetHelperJS suivante assigne le DotNetObjectReference à un élément dans une propriété nommée dotNetHelper. La fonction interopCallJS suivante utilise le DotNetObjectReference de l’élément transmis pour appeler une méthode .NET nommée UpdateMessage.
ListItem2.razor.js :
export function assignDotNetHelper(element, dotNetHelper) {
element.dotNetHelper = dotNetHelper;
}
export async function interopCall(element) {
await element.dotNetHelper.invokeMethodAsync('UpdateMessage');
}
ListItem2.razor.js :
export function assignDotNetHelper(element, dotNetHelper) {
element.dotNetHelper = dotNetHelper;
}
export async function interopCall(element) {
await element.dotNetHelper.invokeMethodAsync('UpdateMessage');
}
<script>
window.assignDotNetHelper = (element, dotNetHelper) => {
element.dotNetHelper = dotNetHelper;
}
window.interopCall = async (element) => {
await element.dotNetHelper.invokeMethodAsync('UpdateMessage');
}
</script>
Note
Pour des conseils généraux concernant l’emplacement JS et nos recommandations pour les applications de production, veuillez consulter la section Emplacement JavaScript dans les applications ASP.NET Core Blazor.
Dans l’exemple précédent, le nom de variable dotNetHelper est arbitraire et peut être remplacé par tout nom préféré.
Le composant ListItem2 suivant est un composant partagé qui peut être utilisé autant de fois que nécessaire dans un composant parent et crée des éléments de liste (<li>...</li>) pour une liste HTML (<ul>...</ul> ou <ol>...</ol>).
Chaque instance du composant ListItem2 appelle la fonction assignDotNetHelperJS dans OnAfterRenderAsync avec une référence d’élément (le premier élément <span> de l’élément de liste) et l’instance du composant en tant que DotNetObjectReference.
Lorsque l’élément ListItem2 de message d’un composant <span> est sélectionné, la fonction interopCallinteropCall est appelée en transmettant l’élément <span> comme paramètre (this), ce qui appelle la méthode .NET UpdateMessage. Dans UpdateMessage, StateHasChanged est appelé pour mettre à jour l’interface utilisateur lorsque message est défini et que la propriété display du second <span> est mise à jour. Si StateHasChanged n’est pas appelé, Blazor ne peut pas savoir que l’interface utilisateur doit être mise à jour lorsque la méthode est invoquée.
Le DotNetObjectReference est supprimé lors de la suppression du composant.
ListItem2.razor :
@inject IJSRuntime JS
@implements IAsyncDisposable
<li>
<span style="font-weight:bold;color:@color" @ref="elementRef"
@onclick="CallJSToInvokeDotnet">
@message
</span>
<span style="display:@display">
Not Updated Yet!
</span>
</li>
@code {
private IJSObjectReference? module;
private DotNetObjectReference<ListItem2>? objRef;
private ElementReference elementRef;
private string display = "inline-block";
private string message = "Select one of these list items.";
private string color = "initial";
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
module = await JS.InvokeAsync<IJSObjectReference>("import",
"./Components/ListItem2.razor.js");
objRef = DotNetObjectReference.Create(this);
await module.InvokeVoidAsync("assignDotNetHelper", elementRef, objRef);
}
}
public async Task CallJSToInvokeDotnet()
{
if (module is not null)
{
await module.InvokeVoidAsync("interopCall", elementRef);
}
}
[JSInvokable]
public void UpdateMessage()
{
message = "UpdateMessage Called!";
display = "none";
color = "MediumSeaGreen";
StateHasChanged();
}
async ValueTask IAsyncDisposable.DisposeAsync()
{
if (module is not null)
{
try
{
await module.DisposeAsync();
}
catch (JSDisconnectedException)
{
}
}
objRef?.Dispose();
}
}
@inject IJSRuntime JS
@implements IAsyncDisposable
<li>
<span style="font-weight:bold;color:@color" @ref="elementRef"
@onclick="CallJSToInvokeDotnet">
@message
</span>
<span style="display:@display">
Not Updated Yet!
</span>
</li>
@code {
private IJSObjectReference? module;
private DotNetObjectReference<ListItem2>? objRef;
private ElementReference elementRef;
private string display = "inline-block";
private string message = "Select one of these list items.";
private string color = "initial";
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
module = await JS.InvokeAsync<IJSObjectReference>("import",
"./Components/ListItem2.razor.js");
objRef = DotNetObjectReference.Create(this);
await module.InvokeVoidAsync("assignDotNetHelper", elementRef, objRef);
}
}
public async Task CallJSToInvokeDotnet()
{
if (module is not null)
{
await module.InvokeVoidAsync("interopCall", elementRef);
}
}
[JSInvokable]
public void UpdateMessage()
{
message = "UpdateMessage Called!";
display = "none";
color = "MediumSeaGreen";
StateHasChanged();
}
async ValueTask IAsyncDisposable.DisposeAsync()
{
if (module is not null)
{
try
{
await module.DisposeAsync();
}
catch (JSDisconnectedException)
{
}
}
objRef?.Dispose();
}
}
@inject IJSRuntime JS
<li>
<span @ref="elementRef" onclick="interopCall(this)">@message</span>
<span style="display:@display">Not Updated Yet!</span>
</li>
@code {
private DotNetObjectReference<ListItem2>? objRef;
private ElementReference elementRef;
private string display = "inline-block";
private string message = "Select one of these list items.";
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
objRef = DotNetObjectReference.Create(this);
await JS.InvokeVoidAsync("assignDotNetHelper", elementRef, objRef);
}
}
[JSInvokable]
public void UpdateMessage()
{
message = "UpdateMessage Called!";
display = "none";
StateHasChanged();
}
public void Dispose() => objRef?.Dispose();
}
@inject IJSRuntime JS
<li>
<span @ref="elementRef" onclick="interopCall(this)">@message</span>
<span style="display:@display">Not Updated Yet!</span>
</li>
@code {
private DotNetObjectReference<ListItem2>? objRef;
private ElementReference elementRef;
private string display = "inline-block";
private string message = "Select one of these list items.";
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
objRef = DotNetObjectReference.Create(this);
await JS.InvokeVoidAsync("assignDotNetHelper", elementRef, objRef);
}
}
[JSInvokable]
public void UpdateMessage()
{
message = "UpdateMessage Called!";
display = "none";
StateHasChanged();
}
public void Dispose() => objRef?.Dispose();
}
@inject IJSRuntime JS
<li>
<span @ref="elementRef" onclick="interopCall(this)">@message</span>
<span style="display:@display">Not Updated Yet!</span>
</li>
@code {
private DotNetObjectReference<ListItem2> objRef;
private ElementReference elementRef;
private string display = "inline-block";
private string message = "Select one of these list items.";
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
objRef = DotNetObjectReference.Create(this);
await JS.InvokeVoidAsync("assignDotNetHelper", elementRef, objRef);
}
}
[JSInvokable]
public void UpdateMessage()
{
message = "UpdateMessage Called!";
display = "none";
StateHasChanged();
}
public void Dispose() => objRef?.Dispose();
}
@inject IJSRuntime JS
<li>
<span @ref="elementRef" onclick="interopCall(this)">@message</span>
<span style="display:@display">Not Updated Yet!</span>
</li>
@code {
private DotNetObjectReference<ListItem2> objRef;
private ElementReference elementRef;
private string display = "inline-block";
private string message = "Select one of these list items.";
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
objRef = DotNetObjectReference.Create(this);
await JS.InvokeVoidAsync("assignDotNetHelper", elementRef, objRef);
}
}
[JSInvokable]
public void UpdateMessage()
{
message = "UpdateMessage Called!";
display = "none";
StateHasChanged();
}
public void Dispose() => objRef?.Dispose();
}
Le composant parent suivant inclut quatre éléments de liste, chacun étant une instance du composant ListItem2.
CallDotnet7.razor :
@page "/call-dotnet-7"
<PageTitle>Call .NET 7</PageTitle>
<h1>Call .NET Example 7</h1>
<ul>
<ListItem2 />
<ListItem2 />
<ListItem2 />
<ListItem2 />
</ul>
CallDotnet7.razor :
@page "/call-dotnet-7"
<PageTitle>Call .NET 7</PageTitle>
<h1>Call .NET Example 7</h1>
<ul>
<ListItem2 />
<ListItem2 />
<ListItem2 />
<ListItem2 />
</ul>
CallDotNetExample7.razor :
@page "/call-dotnet-example-7"
<h1>Call .NET Example 7</h1>
<ul>
<ListItem2 />
<ListItem2 />
<ListItem2 />
<ListItem2 />
</ul>
CallDotNetExample7.razor :
@page "/call-dotnet-example-7"
<h1>Call .NET Example 7</h1>
<ul>
<ListItem2 />
<ListItem2 />
<ListItem2 />
<ListItem2 />
</ul>
CallDotNetExample7.razor :
@page "/call-dotnet-example-7"
<h1>Call .NET Example 7</h1>
<ul>
<ListItem2 />
<ListItem2 />
<ListItem2 />
<ListItem2 />
</ul>
CallDotNetExample7.razor :
@page "/call-dotnet-example-7"
<h1>Call .NET Example 7</h1>
<ul>
<ListItem2 />
<ListItem2 />
<ListItem2 />
<ListItem2 />
</ul>
Interopérabilité JS synchrone dans les composants côté client
Cette section ne s'applique qu'aux composants côté client.
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. Sur le serveur, tous les appels d’interopérabilité JS doivent être asynchrones, car ils sont envoyés via une connexion réseau.
Si vous êtes certain que votre composant s’exécute uniquement sur WebAssembly, vous pouvez choisir de faire des appels d’interopérabilité JS synchrones. Cela représente un peu moins de surcharge que d’effectuer des appels asynchrones, et peut entraîner moins de cycles de rendu, car il n’y a pas d’état intermédiaire lors de l’attente des résultats.
Pour effectuer un appel synchrone de JavaScript vers .NET dans un composant côté client, utilisez DotNet.invokeMethod au lieu de DotNet.invokeMethodAsync.
Les appels synchrones fonctionnent si :
Emplacement JavaScript
Chargez du code JavaScript (JS) à l’aide de l’une des approches décrites dans l’article sur l’emplacement JavaScript :
-
Charger un script dans le balisage
<head>(pas généralement recommandé) -
Charger un script dans le balisage
<body> -
Charger un script à partir d’un fichier JavaScript externe (
.js) colocalisé avec un composant -
Charger un script à partir d’un fichier JavaScript externe (
.js) - Injecter un script avant ou après que Blazor démarre
L’utilisation de modules JS pour charger JS est décrite dans cet article dans la section Isolation JavaScript dans les modules JavaScript.
Warning
Placez une balise <script> dans un fichier composant (.razor) uniquement si le composant adopte le rendu statique côté serveur (static SSR), car la balise <script> ne peut pas être mise à jour dynamiquement.
Warning
Ne placez pas une balise <script> dans un fichier de composant (.razor) car la balise <script> ne peut pas être mise à jour dynamiquement.
Isolation JavaScript dans les modules JavaScript
Blazor active l’isolation JavaScript (JS) dans les modules JavaScript standard (spécification ECMAScript). Le chargement de module JavaScript fonctionne de la même manière dans Blazor que pour d’autres types d’applications web, et vous êtes libre de personnaliser la façon dont les modules sont définis dans votre application. Pour obtenir un guide sur l’utilisation des modules JavaScript, consultez MDN Web Docs : modules JavaScript.
L’isolation JS offre les avantages suivants :
- Le code JS importé ne pollue plus l’espace de noms global.
- Les consommateurs d’une bibliothèque et de composants ne sont pas tenus d’importer le code JS associé.
Pour plus d’informations, consultez Appeler des fonctions JavaScript à partir de méthodes .NET dans ASP.NET Core Blazor.
L’importation dynamique avec l’import()opérateur est prise en charge avec ASP.NET Core et Blazor :
if ({CONDITION}) import("/additionalModule.js");
Dans l’exemple précédent, l’espace {CONDITION} réservé représente une vérification conditionnelle pour déterminer si le module doit être chargé.
Pour la compatibilité du navigateur, consultez Puis-je utiliser : modules JavaScript : importation dynamique.
Éviter les références d’objets circulaires
Les objets qui contiennent des références circulaires ne peuvent pas être sérialisés sur le client pour :
- Les appels de méthode .NET.
- Les appels de méthode JavaScript à partir de C# lorsque le type de retour a des références circulaires.
Prise en charge des tableaux d’octets
Blazor prend en charge l’interopérabilité JavaScript (JS) des tableaux d’octets optimisés, qui évite l’encodage/décodage des tableaux d’octets en Base64. L’exemple suivant utilise l’interopérabilité JS pour passer un tableau d’octets à .NET.
Fournissez une fonction sendByteArrayJS. La fonction est appelée statiquement (elle inclut le nom de l’assembly dans l’appel invokeMethodAsync) par un bouton dans le composant et ne retourne pas de valeur :
CallDotnet8.razor.js :
export function sendByteArray() {
const data = new Uint8Array([0x45, 0x76, 0x65, 0x72, 0x79, 0x74, 0x68, 0x69,
0x6e, 0x67, 0x27, 0x73, 0x20, 0x73, 0x68, 0x69, 0x6e, 0x79, 0x2c,
0x20, 0x43, 0x61, 0x70, 0x74, 0x61, 0x69, 0x6e, 0x2e, 0x20, 0x4e,
0x6f, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x66, 0x72, 0x65, 0x74, 0x2e]);
DotNet.invokeMethodAsync('BlazorSample', 'ReceiveByteArray', data)
.then(str => {
alert(str);
});
}
export function addHandlers() {
const btn = document.getElementById("btn");
btn.addEventListener("click", sendByteArray);
}
<script>
window.sendByteArray = () => {
const data = new Uint8Array([0x45,0x76,0x65,0x72,0x79,0x74,0x68,0x69,
0x6e,0x67,0x27,0x73,0x20,0x73,0x68,0x69,0x6e,0x79,0x2c,
0x20,0x43,0x61,0x70,0x74,0x61,0x69,0x6e,0x2e,0x20,0x4e,
0x6f,0x74,0x20,0x74,0x6f,0x20,0x66,0x72,0x65,0x74,0x2e]);
DotNet.invokeMethodAsync('BlazorSample', 'ReceiveByteArray', data)
.then(str => {
alert(str);
});
};
</script>
Note
Pour des conseils généraux concernant l’emplacement JS et nos recommandations pour les applications de production, veuillez consulter la section Emplacement JavaScript dans les applications ASP.NET Core Blazor.
CallDotnet8.razor :
@page "/call-dotnet-8"
@using System.Text
@implements IAsyncDisposable
@inject IJSRuntime JS
<PageTitle>Call .NET 8</PageTitle>
<h1>Call .NET Example 8</h1>
<p>
<button id="btn">Send Bytes</button>
</p>
<p>
Quote ©2005 <a href="https://www.uphe.com">Universal Pictures</a>:
<a href="https://www.uphe.com/movies/serenity-2005">Serenity</a><br>
<a href="https://www.imdb.com/name/nm0821612/">Jewel Staite on IMDB</a>
</p>
@code {
private IJSObjectReference? module;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
module = await JS.InvokeAsync<IJSObjectReference>("import",
"./Components/Pages/CallDotnet8.razor.js");
await module.InvokeVoidAsync("addHandlers");
}
}
[JSInvokable]
public static Task<string> ReceiveByteArray(byte[] receivedBytes) =>
Task.FromResult(Encoding.UTF8.GetString(receivedBytes, 0,
receivedBytes.Length));
async ValueTask IAsyncDisposable.DisposeAsync()
{
if (module is not null)
{
try
{
await module.DisposeAsync();
}
catch (JSDisconnectedException)
{
}
}
}
}
CallDotnet8.razor :
@page "/call-dotnet-8"
@using System.Text
@implements IAsyncDisposable
@inject IJSRuntime JS
<PageTitle>Call .NET 8</PageTitle>
<h1>Call .NET Example 8</h1>
<p>
<button id="btn">Send Bytes</button>
</p>
<p>
Quote ©2005 <a href="https://www.uphe.com">Universal Pictures</a>:
<a href="https://www.uphe.com/movies/serenity-2005">Serenity</a><br>
<a href="https://www.imdb.com/name/nm0821612/">Jewel Staite on IMDB</a>
</p>
@code {
private IJSObjectReference? module;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
module = await JS.InvokeAsync<IJSObjectReference>("import",
"./Components/Pages/CallDotnet8.razor.js");
await module.InvokeVoidAsync("addHandlers");
}
}
[JSInvokable]
public static Task<string> ReceiveByteArray(byte[] receivedBytes) =>
Task.FromResult(Encoding.UTF8.GetString(receivedBytes, 0,
receivedBytes.Length));
async ValueTask IAsyncDisposable.DisposeAsync()
{
if (module is not null)
{
try
{
await module.DisposeAsync();
}
catch (JSDisconnectedException)
{
}
}
}
}
CallDotNetExample8.razor :
@page "/call-dotnet-example-8"
@using System.Text
<PageTitle>Call .NET 8</PageTitle>
<h1>Call .NET Example 8</h1>
<p>
<button onclick="sendByteArray()">Send Bytes</button>
</p>
<p>
Quote ©2005 <a href="https://www.uphe.com">Universal Pictures</a>:
<a href="https://www.uphe.com/movies/serenity-2005">Serenity</a><br>
<a href="https://www.imdb.com/name/nm0821612/">Jewel Staite on IMDB</a>
</p>
@code {
[JSInvokable]
public static Task<string> ReceiveByteArray(byte[] receivedBytes)
{
return Task.FromResult(
Encoding.UTF8.GetString(receivedBytes, 0, receivedBytes.Length));
}
}
CallDotNetExample8.razor :
@page "/call-dotnet-example-8"
@using System.Text
<h1>Call .NET Example 8</h1>
<p>
<button onclick="sendByteArray()">Send Bytes</button>
</p>
<p>
Quote ©2005 <a href="https://www.uphe.com">Universal Pictures</a>:
<a href="https://www.uphe.com/movies/serenity-2005">Serenity</a><br>
<a href="https://www.imdb.com/name/nm0821612/">Jewel Staite on IMDB</a>
</p>
@code {
[JSInvokable]
public static Task<string> ReceiveByteArray(byte[] receivedBytes)
{
return Task.FromResult(
Encoding.UTF8.GetString(receivedBytes, 0, receivedBytes.Length));
}
}
Pour savoir comment utiliser un tableau d’octets lors d’un appel de JavaScript depuis .NET, veuillez consulter la section Appeler des fonctions JavaScript depuis des méthodes .NET dans ASP.NET Core Blazor.
Diffuser en continu de JavaScript vers .NET
Blazor prend en charge le streaming de données directement de JavaScript vers .NET. Les flux sont demandés via l’interface Microsoft.JSInterop.IJSStreamReference.
Microsoft.JSInterop.IJSStreamReference.OpenReadStreamAsync retourne un Stream et utilise les paramètres suivants :
-
maxAllowedSize: nombre maximal d’octets autorisés pour l’opération de lecture depuis JavaScript, par défaut 512 000 octets si non spécifié. -
cancellationToken: un CancellationToken permettant d’annuler la lecture.
En JavaScript :
function streamToDotNet() {
return new Uint8Array(10000000);
}
Dans le code C# :
var dataReference =
await JS.InvokeAsync<IJSStreamReference>("streamToDotNet");
using var dataReferenceStream =
await dataReference.OpenReadStreamAsync(maxAllowedSize: 10_000_000);
var outputPath = Path.Combine(Path.GetTempPath(), "file.txt");
using var outputFileStream = File.OpenWrite(outputPath);
await dataReferenceStream.CopyToAsync(outputFileStream);
Dans l'exemple précédent :
-
JSest une instance injectée de IJSRuntime. IJSRuntime est inscrit par le framework Blazor. - Le
dataReferenceStreamest écrit sur le disque (file.txt) dans le chemin du dossier temporaire de l’utilisateur actuel (GetTempPath).
Appeler des fonctions JavaScript depuis des méthodes .NET dans ASP.NET Core Blazor couvre l’opération inverse, à savoir le streaming de .NET vers JavaScript à l’aide d’un DotNetStreamReference.
Uploads de fichiers dans ASP.NET Core Blazor couvre comment téléverser un fichier dans Blazor. Pour consulter un exemple de formulaire qui streame des données <textarea> dans un composant côté serveur, veuillez consulter la section Résolution des problèmes de formulaires ASP.NET Core Blazor.
Interopérabilité JavaScript [JSImport]/[JSExport]
Cette section s’applique aux composants côté client.
Pour une alternative à l’interaction avec JavaScript (JS) dans les composants côté client en utilisant le mécanisme d’interopérabilité Blazor de JS basé sur l’interface IJSRuntime, une API d’interopérabilité JS[JSImport]/[JSExport] est disponible pour les applications ciblant .NET 7 ou les versions ultérieures.
Pour plus d’informations, veuillez consulter la section Interopérabilité JavaScript JSImport/JSExport avec ASP.NET Core Blazor.
Suppression des références d’objets d’interopérabilité JavaScript
Les exemples des articles d’interopérabilité JavaScript (JS) illustrent des modèles de suppression d’objets classiques :
Lors de l’appel de .NET depuis JS, comme décrit dans cette rubrique, supprimez la DotNetObjectReference créée soit depuis .NET soit depuis JS afin d’éviter les fuites de mémoire .NET.
Lors de l’appel JS à partir de .NET, comme décrit dans Appeler des fonctions JavaScript à partir de méthodes .NET dans ASP.NET Core Blazor, éliminez les fonctions créées IJSObjectReference/IJSInProcessObjectReference/
JSObjectReferenceà partir de .NET ou de JS pour éviter toute fuite de JS mémoire.
Les références d’objet d’interopérabilité JS sont implémentées en tant que carte avec pour clé un identifiant du côté de l’appel d’interopérabilité JS qui crée la référence. Lorsque l’élimination de l’objet est lancée du côté .NET ou JS, Blazor supprime l’entrée de la carte, et l’objet peut être récupéré en mémoire tant qu’aucune autre référence forte à l’objet n’est présente.
Au minimum, éliminez toujours les objets créés côté .NET pour éviter les fuites de mémoire managée .NET.
Tâches de nettoyage de modèle DOM lors de la suppression des composants
Pour plus d’informations, consultez Interopérabilité JavaScript et ASP.NET Core Blazor (interopérabilité JS).
Appels d’interopérabilité JavaScript sans circuit
Pour plus d’informations, consultez Interopérabilité JavaScript et ASP.NET Core Blazor (interopérabilité JS).
Ressources supplémentaires
- Appeler des fonctions JavaScript à partir de méthodes .NET dans ASP.NET Core Blazor
-
Exemple
InteropComponent.razor(référentiel GitHubdotnet/AspNetCore, branchemain) : la branchemainreprésente le développement en cours de l’unité produit pour la prochaine version d’ASP.NET Core. Pour sélectionner la branche d’une autre version (par exemple,release/{VERSION}, où l’espace réservé{VERSION}représente la version de la release), utilisez la liste déroulante Basculer entre les branches ou les étiquettes pour sélectionner la branche. Pour une branche qui n’existe plus, utilisez l’onglet Balises pour trouver l’API (par exemple,v7.0.0). - Interaction avec le DOM
-
BlazorExemples Référentiel GitHub (
dotnet/blazor-samples) (comment télécharger) - Gérer les erreurs dans les applications ASP.NET CoreBlazor (section Interopérabilité JavaScript)
- Réduction des menaces : méthodes .NET appelées depuis le navigateur