Appeler des méthodes .NET à partir de fonctions JavaScript dans ASP.NET Core Blazor
Remarque
Ceci n’est pas la dernière version de cet article. Pour la version actuelle, consultez la version .NET 8 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 prise en charge de .NET et .NET Core. Pour la version actuelle, consultez la version .NET 8 de cet article.
Important
Ces informations portent sur la préversion du produit, qui est susceptible d’être en grande partie modifié avant sa commercialisation. Microsoft n’offre aucune garantie, expresse ou implicite, concernant les informations fournies ici.
Pour la version actuelle, consultez la version .NET 8 de cet article.
Cet article explique comment appeler des méthodes .NET à partir de JavaScript (JS).
Pour plus d’informations sur l’appel de fonctions JS à partir de .NET, consultez Appeler des fonctions JavaScript à partir de méthodes .NET dans ASP.NET Core Blazor.
Appeler une méthode .NET statique
Pour appeler une méthode .NET statique à partir de JavaScript (JS), utilisez les fonctions JS :
DotNet.invokeMethodAsync
(recommandé) : asynchrone pour les composants côté serveur et côté client.DotNet.invokeMethod
: synchrone uniquement pour les composants côté client uniquement.
Transmettez le nom de l’assembly contenant la méthode, l’identificateur de la méthode .NET statique et les arguments éventuels.
Dans l’exemple suivant :
- L’espace réservé
{ASSEMBLY NAME}
est le nom de l’assembly de l’application. - L’espace réservé
{.NET METHOD ID}
est l’identificateur de méthode .NET. - L’espace réservé
{ARGUMENTS}
reçoit des arguments facultatifs séparés par des virgules à transmettre à la méthode, chacun d’entre eux devant être sérialisable en JSON.
DotNet.invokeMethodAsync('{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 avoir l’attribut [JSInvokable]
.
Dans l’exemple suivant :
- L’espace réservé
{<T>}
indique le type de retour, qui est uniquement requis pour les méthodes qui retournent une valeur. - L’espace réservé
{.NET METHOD ID}
est l’identificateur de méthode.
@code {
[JSInvokable]
public static Task{<T>} {.NET METHOD ID}()
{
...
}
}
Remarque
L’appel de méthodes génériques ouvertes n’est pas pris en charge avec les méthodes .NET statiques, mais l’est avec les méthodes d’instance. Pour plus d’informations, consultez la section Appeler des méthodes de classe génériques .NET.
Dans le composant suivant, la méthode C# ReturnArrayAsync
retourne un tableau int
. L’attribut [JSInvokable]
est appliqué à la méthode, ce qui rend la méthode disponible pour 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)
{
await module.DisposeAsync();
}
}
}
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 addHandlers
JS ajoute un événement click
au bouton. La fonction returnArrayAsync
JS est affectée en tant que gestionnaire.
La fonction returnArrayAsync
JS appelle la méthode .NET ReturnArrayAsync
du composant, ce qui enregistre le résultat dans la console des outils de développement web du navigateur. BlazorSample
est le 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)
{
await module.DisposeAsync();
}
}
}
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 addHandlers
JS ajoute un événement click
au bouton. La fonction returnArrayAsync
JS est affectée en tant que gestionnaire.
La fonction returnArrayAsync
JS appelle la méthode .NET ReturnArrayAsync
du composant, ce qui enregistre le résultat dans la console des outils de développement web du navigateur. BlazorSample
est le 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 onclick
de l’élément <button>
est l’attribution de gestionnaire d’événements onclick
JavaScript pour le traitement des événements click
, et non pas l’attribut de directive @onclick
de Blazor. La fonction returnArrayAsync
JS est affectée en tant que gestionnaire.
La fonction returnArrayAsync
JS suivante appelle la méthode .NET ReturnArrayAsync
du composant, ce qui enregistre le résultat dans la console des outils de développement web du navigateur. BlazorSample
est le nom de l’assembly de l’application.
<script>
window.returnArrayAsync = () => {
DotNet.invokeMethodAsync('BlazorSample', 'ReturnArrayAsync')
.then(data => {
console.log(data);
});
};
</script>
Remarque
Pour obtenir une aide générale sur l’emplacement deJS et nos recommandations pour les applications de production, consultez Emplacement de JavaScript dans les applications Blazor ASP.NET Core.
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 de la sortie diffère légèrement d’un navigateur à l’autre. La sortie suivante montre 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 en tant qu’arguments.
Pour illustrer le passage de données à .NET, passez une position de départ à la méthode ReturnArrayAsync
dans laquelle 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
disponible du composant reçoit la position de départ et construit le tableau à partir de celle-ci. Le tableau est retourné pour la journalisation dans la console :
[JSInvokable]
public static Task<int[]> ReturnArrayAsync(int startPosition) =>
Task.FromResult(Enumerable.Range(startPosition, 3).ToArray());
Une fois l’application recompilée et le navigateur actualisé, la sortie suivante s’affiche dans la console du navigateur lorsque le bouton est sélectionné :
Array(3) [ 14, 15, 16 ]
L’identificateur de méthode .NET pour l’appel JS est le nom de la méthode .NET, mais vous pouvez spécifier un identificateur différent à l’aide du constructeur d’attribut [JSInvokable]
. Dans l’exemple suivant, DifferentMethodName
est l’identificateur de méthode attribué pour 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)
Remarque
L’exemple de méthode ReturnArrayAsync
de cette section retourne le résultat d’un Task sans utiliser de mots clés C# async
et await
explicites. Le codage de méthodes avec async
et await
est typique des méthodes qui utilisent le mot clé await
pour retourner la valeur des opérations asynchrones.
Méthode composée ReturnArrayAsync
avec des 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, consultez Programmation asynchrone avec async et await dans le guide C#.
Créer des références d’objet et de données JavaScript à passer à .NET
Appelez DotNet.createJSObjectReference(jsObject)
pour construire une référence d’objet JS afin qu’elle puisse être transmise à .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 window
non sérialisable à .NET, qui le reçoit dans la méthode C# ReceiveWindowObject
en tant que IJSObjectReference :
DotNet.invokeMethodAsync('{ASSEMBLY NAME}', 'ReceiveWindowObject',
DotNet.createJSObjectReference(window));
[JSInvokable]
public static void ReceiveWindowObject(IJSObjectReference objRef)
{
...
}
Dans l’exemple précédent, l’espace réservé {ASSEMBLY NAME}
est l’espace de noms de l’application.
Remarque
L’exemple précédent ne nécessite pas de suppression du JSObjectReference
, car aucune référence à l’objet window
n’est conservée dans JS.
La conservation d’une référence à un JSObjectReference
nécessite la suppression de celle-ci pour éviter les fuites de mémoire JS sur le 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('{ASSEMBLY NAME}', 'ReceiveWindowObject', jsObjectReference);
DotNet.disposeJSObjectReference(jsObjectReference);
Dans l’exemple précédent, l’espace réservé {ASSEMBLY NAME}
est l’espace de noms de l’application.
Appelez DotNet.createJSStreamReference(streamReference)
pour construire une référence de flux JS afin qu’elle puisse être transmise à .NET, où streamReference
est un ArrayBuffer
, Blob
ou tout tableau typé, comme 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 à partir de JavaScript (JS) :
Transmettez l’instance .NET par référence à JS en encapsulant l’instance dans un DotNetObjectReference et en appelant Create dessus.
Appelez une méthode d’instance .NET à partir de JS en utilisant
invokeMethodAsync
(recommandé) ouinvokeMethod
(composants côté client uniquement) à partir de l’instance DotNetObjectReference passée. Transmettez l’identificateur de la méthode .NET d’instance et les arguments éventuels. L’instance .NET peut également être passée en tant qu’argument lors de l’appel d’autres méthodes .NET à partir de JS.Dans l’exemple suivant :
dotNetHelper
est un DotNetObjectReference.- L’espace réservé
{.NET METHOD ID}
est l’identificateur de méthode .NET. - L’espace réservé
{ARGUMENTS}
reçoit des arguments facultatifs séparés par des virgules à transmettre à la méthode, chacun d’entre eux devant être sérialisable en JSON.
dotNetHelper.invokeMethodAsync('{.NET METHOD ID}', {ARGUMENTS});
Remarque
invokeMethodAsync
etinvokeMethod
n’acceptent pas de paramètre de nom d’assembly lors de l’appel d’une méthode d’instance.invokeMethodAsync
retourne un JSPromise
représentant le résultat de l’opération.invokeMethod
(composants côté client uniquement) 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 cet article illustrent différentes approches pour appeler une méthode .NET d’instance :
Évitez de découper les méthodes .NET disponibles pour JavaScript
Cette section s’applique aux applications côté client avec la compilation à l’avance (AOT) et la liaison dynamique à l’exécution activées.
Plusieurs des exemples des sections suivantes sont basés sur une approche d’instance de classe, où la méthode .NET disponible pour JavaScript marquée avec l’attribut [JSInvokable]
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 la nouvelle liaison/le découpage du runtime. Pour protéger les méthodes .NET contre le découpage en dehors des composants Razor, implémentez les méthodes avec l’attribut DynamicDependency
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, consultez Préparer des bibliothèques .NET pour le découpage : DynamicDependency.
Passer une DotNetObjectReference
à une fonction JavaScript individuelle
L’exemple de cette section montre comment passer une DotNetObjectReference à une fonction JavaScript individuelle (JS).
La fonction sayHello1
JS suivante reçoit DotNetObjectReference et appelle invokeMethodAsync
pour appeler la méthode .NET GetHelloMessage
d’un composant :
<script>
window.sayHello1 = (dotNetHelper) => {
return dotNetHelper.invokeMethodAsync('GetHelloMessage');
};
</script>
Remarque
Pour obtenir une aide générale sur l’emplacement deJS et nos recommandations pour les applications de production, consultez Emplacement de JavaScript dans les applications Blazor ASP.NET Core.
Dans l’exemple précédent, le nom de variable dotNetHelper
est arbitraire et peut être remplacé par n’importe quel nom de votre choix.
Pour le composant suivant :
- Le composant a une méthode .NET disponible pour JS nommée
GetHelloMessage
. - Lorsque le bouton
Trigger .NET instance method
est sélectionné, la fonction JSsayHello1
est appelée avec la DotNetObjectReference. sayHello1
:- Appelle
GetHelloMessage
et reçoit le résultat du message. - Retourne le résultat du message à la méthode
TriggerDotNetInstanceMethod
appelante.
- Appelle
- Le message retourné à partir de
sayHello1
dansresult
s’affiche à l’utilisateur. - Pour éviter une fuite de mémoire et autoriser le nettoyage de la mémoire, 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 n’importe quel nom de votre choix.
Utilisez les instructions suivantes pour passer des arguments à une méthode d’instance :
Ajoutez des paramètres à l’appel de méthode .NET. Dans l’exemple suivant, un nom est passé à la méthode. Ajoutez des paramètres supplémentaires à la liste en fonction de vos besoins.
<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 n’importe quel nom de votre choix.
Fournissez la liste des 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 n’importe quel nom de votre choix.
Passer une DotNetObjectReference
à une classe avec plusieurs fonctions JavaScript
L’exemple de cette section montre comment passer une DotNetObjectReference à une classe JavaScript (JS) avec plusieurs fonctions.
Créez et passez une DotNetObjectReference de la méthode de cycle de vie OnAfterRenderAsync
à une classe JS que plusieurs fonctions utiliseront. Assurez-vous que le code .NET supprime 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 la directive d’attribut @onclick
de Blazor.
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)
{
await module.DisposeAsync();
}
dotNetHelper?.Dispose();
}
}
Dans l'exemple précédent :
JS
est un instance IJSRuntime injectée. IJSRuntime est inscrit par le framework Blazor.- Le nom de variable
dotNetHelper
est arbitraire et peut être remplacé par n’importe quel nom de votre choix. - Le composant doit explicitement éliminer DotNetObjectReference pour autoriser le nettoyage de la mémoire et empêcher une fuite de mémoire.
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 n’importe quel nom de votre choix.
@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 :
JS
est un instance IJSRuntime injectée. IJSRuntime est inscrit par le framework Blazor.- Le nom de variable
dotNetHelper
est arbitraire et peut être remplacé par n’importe quel nom de votre choix. - Le composant doit explicitement éliminer DotNetObjectReference pour autoriser le nettoyage de la mémoire et empêcher 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
GreetingHelpers
est ajoutée à l’objetwindow
pour définir globalement la classe, ce qui permet à Blazor de localiser la classe pour l’interopérabilité JS. - Le nom de variable
dotNetHelper
est arbitraire et peut être remplacé par n’importe quel nom de votre choix.
Remarque
Pour obtenir une aide générale sur l’emplacement deJS et nos recommandations pour les applications de production, consultez Emplacement de JavaScript dans les applications Blazor ASP.NET Core.
Appeler des méthodes de classe génériques .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 de type générique suivante (GenericType<TValue>
) :
- La classe a un paramètre de type unique (
TValue
) avec une propriété génériqueValue
unique. - La classe a 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
:Update
met à jour de manière synchrone la valeur deValue
à partir denewValue
.UpdateAsync
met à jour de manière asynchrone la valeur deValue
à partir denewValue
après la création d’une tâche pouvant être attendue, avec Task.Yield qui retourne de façon asynchrone au contexte actuel en cas d’attente.
- Chacune des méthodes de la classe écrit le type de
TValue
et la valeur deValue
dans la console. L’écriture dans la console est effectuée uniquement à des fins de démonstration. Les applications de production évitent généralement d’écrire dans la console et préfèrent la journalisation de l’application. Pour plus d’informations, consultez Journalisation dans ASP.NET Core Blazor et Journalisation dans .NET Core et ASP.NET Core.
Remarque
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 illustrent les génériques fermés, mais l’appel de méthodes d’instance d’interopérabilité JS 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éthode .NET statiques, décrits plus haut dans cet article.
Pour plus d’informations, 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 void UpdateAsync(TValue newValue)
{
await Task.Yield();
Value = newValue;
Console.WriteLine($"UpdateAsync: GenericType<{typeof(TValue)}>: {Value}");
}
}
Dans la fonction invokeMethodsAsync
suivante :
- Les méthodes
Update
etUpdateAsync
de la classe de type générique sont appelées avec des arguments représentant des chaînes et des nombres. - Les composants côté client prennent en charge l’appel de méthodes .NET de manière synchrone avec
invokeMethod
.syncInterop
reçoit une valeur booléenne indiquant si l’interopérabilité JS se produit dans le client. QuandsyncInterop
esttrue
,invokeMethod
est appelé de façon sécurisée. Si la valeur desyncInterop
estfalse
, seule la fonction asynchroneinvokeMethodAsync
est appelée, car l’interopérabilité JS s’exécute dans un composant côté serveur. - À des fins de démonstration, l’appel de fonction DotNetObjectReference (
invokeMethod
ouinvokeMethodAsync
), la méthode .NET appelée (Update
ouUpdateAsync
) et l’argument sont écrits dans la console. Les arguments utilisent un nombre aléatoire pour permettre la correspondance de l’appel de fonction JS à l’appel de méthode .NET (également écrit dans la console côté .NET). Le code de production n’écrit généralement pas dans la console, ni sur le client ni sur le serveur. Les applications de production s’appuient généralement sur la journalisation de l’application. Pour plus d’informations, consultez Journalisation dans ASP.NET Core Blazor et Journalisation dans .NET Core 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>
Remarque
Pour obtenir une aide générale sur l’emplacement deJS et nos recommandations pour les applications de production, consultez Emplacement de JavaScript dans les applications Blazor ASP.NET Core.
Dans le composant GenericsExample
suivant :
- La fonction JS
invokeMethodsAsync
est appelée lorsque le boutonInvoke Interop
est sélectionné. - Une paire de types DotNetObjectReference est créée et transmise à la fonction JS pour les instances de
GenericType
en tant questring
etint
.
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 IJSRuntime injectée. IJSRuntime est inscrit par le framework Blazor.
L’exemple suivant illustre la sortie classique 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: Update: GenericType<System.String>: string 26784
JS: invokeMethodAsync:Update(14107)
.NET: Update: GenericType<System.Int32>: 14107
JS: invokeMethodAsync:UpdateAsync(48995)
JS: invokeMethod:Update(12872)
.NET: Update: 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 classique d’un composant côté serveur :
JS: invokeMethodAsync:Update(’string 34809’)
.NET: Update: GenericType<System.String>: string 34809
JS: invokeMethodAsync:UpdateAsync(’string 93059’)
JS: invokeMethodAsync:Update(41997)
.NET: Update: 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 en fonction de plusieurs facteurs, notamment la planification des threads et la vitesse d’exécution de la méthode. Il n’est pas possible de prédire de manière fiable l’ordre d’achèvement des appels de méthode asynchrones.
Exemples d’instance de classe
La fonction sayHello1
JS suivante :
- Appelle la méthode
GetHelloMessage
.NET sur la DotNetObjectReference passée. - Retourne le message de
GetHelloMessage
à l’appelantsayHello1
.
<script>
window.sayHello1 = (dotNetHelper) => {
return dotNetHelper.invokeMethodAsync('GetHelloMessage');
};
</script>
Remarque
Pour obtenir une aide générale sur l’emplacement deJS et nos recommandations pour les applications de production, consultez Emplacement de JavaScript dans les applications Blazor ASP.NET Core.
Dans l’exemple précédent, le nom de variable dotNetHelper
est arbitraire et peut être remplacé par n’importe quel nom de votre choix.
La classe HelloHelper
suivante a une méthode .NET disponible pour JS nommée GetHelloMessage
. Quand HelloHelper
est créé, le nom de la propriété Name
est utilisé pour renvoyer un message à partir de 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
de la classe JsInteropClasses3
suivante appelle la fonction JS sayHello1
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 autoriser le nettoyage de la mémoire, la référence d’objet .NET créée par DotNetObjectReference est supprimée lorsque la référence d’objet sort de l’étendue avec 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
. Une fois le bouton sélectionné, Hello, Amy Pond!
s’affiche dans l’interface utilisateur :
Le modèle précédent indiqué dans la classe JsInteropClasses3
peut également être implémenté entièrement 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 autoriser le nettoyage de la mémoire, la référence d’objet .NET créée par DotNetObjectReference est supprimée lorsque la référence d’objet sort de l’étendue avec la syntaxe using var
.
La sortie affichée par le composant est Hello, Amy Pond!
lorsque le nom Amy Pond
est fourni 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 du client en appelant dispose
sur le DotNetObjectReference passé :
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}
est le nom de la fonction JS. - Le nom de variable
dotNetHelper
est arbitraire et peut être remplacé par n’importe quel nom de votre choix. - L’espace réservé
{.NET METHOD ID}
est l’identificateur de méthode .NET.
Classe d’assistance de méthode .NET d’instance de composant
Une classe d’assistance peut appeler une méthode d’instance .NET en tant que Action. Les classes d’assistance sont utiles dans les 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
ListItem1
composants. - Chaque composant
ListItem1
est composé d’un message et d’un bouton. - Lorsqu’un bouton de composant
ListItem1
est sélectionné, la méthodeUpdateMessage
de ceListItem1
modifie le texte de l’élément de liste et masque le bouton.
La classe MessageUpdateInvokeHelper
suivante gère une méthode .NET disponible pour JS, UpdateMessageCaller
, pour appeler le Action spécifié lorsque la classe est instanciée.
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 updateMessageCaller
JS suivante appelle la méthode .NET UpdateMessageCaller
.
<script>
window.updateMessageCaller = (dotNetHelper) => {
dotNetHelper.invokeMethodAsync('UpdateMessageCaller');
dotNetHelper.dispose();
}
</script>
Remarque
Pour obtenir une aide générale sur l’emplacement deJS et nos recommandations pour les applications de production, consultez Emplacement de JavaScript dans les applications Blazor ASP.NET Core.
Dans l’exemple précédent, le nom de variable dotNetHelper
est arbitraire et peut être remplacé par n’importe quel nom de votre choix.
Le composant ListItem1
suivant est un composant partagé qui peut être utilisé n’importe quel nombre de fois dans un composant parent, et qui crée des éléments de liste (<li>...</li>
) pour une liste HTML (<ul>...</ul>
ou <ol>...</ol>
). Chaque instance de composant ListItem1
établit une instance de MessageUpdateInvokeHelper
avec une Action définie sur sa méthode UpdateMessage
.
Lorsqu’un bouton InteropCall
d’un composant ListItem1
est sélectionné, updateMessageCaller
est appelé avec un DotNetObjectReference créé pour l’instance de MessageUpdateInvokeHelper
. Cela permet au framework d’appeler UpdateMessageCaller
sur le MessageUpdateInvokeHelper
de cette instance ListItem1
. Le DotNetObjectReference passé 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 n’a aucun moyen de savoir que l’interface utilisateur doit être mise à jour lorsque Action est appelé.
Le composant parent suivant comprend 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 une fois le deuxième bouton InteropCall
sélectionné :
- Le deuxième composant
ListItem1
a affiché le messageUpdateMessage Called!
. - Le bouton
InteropCall
du deuxième composantListItem1
n’est pas visible, car la propriété CSSdisplay
du bouton est définie surnone
.
Méthode .NET d’instance de composant appelée à partir de DotNetObjectReference
affectée à 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 d’élément et l’instance de composant en tant que DotNetObjectReference. La fonction JS attache DotNetObjectReference à l’élément d’une propriété. - Lorsqu’un événement d’élément est appelé dans JS (par exemple,
onclick
), la DotNetObjectReference attachée de l’élément est utilisée pour appeler une méthode .NET.
Comme dans la section de la classe d’assistance de méthode .NET de l’instance de composant, cette approche est utile dans les 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.
- La méthode .NET est appelée à partir d’un événement JS (par exemple,
onclick
), et non à partir 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
ListItem2
est constitué d’un message d’élément de liste<span>
et d’un deuxième<span>
avec une propriété CSSdisplay
définie surinline-block
pour l’affichage. - Lorsqu’un élément de liste de composants
ListItem2
est sélectionné, la méthodeUpdateMessage
de ceListItem2
modifie le texte de l’élément de liste dans le premier<span>
et masque la deuxième<span>
en définissant sa propriétédisplay
surnone
.
La fonction assignDotNetHelper
JS suivante affecte la DotNetObjectReference à un élément d’une propriété nommée dotNetHelper
. La fonction interopCall
JS suivante utilise la DotNetObjectReference de l’élément passé 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>
Remarque
Pour obtenir une aide générale sur l’emplacement deJS et nos recommandations pour les applications de production, consultez Emplacement de JavaScript dans les applications Blazor ASP.NET Core.
Dans l’exemple précédent, le nom de variable dotNetHelper
est arbitraire et peut être remplacé par n’importe quel nom de votre choix.
Le composant ListItem2
suivant est un composant partagé qui peut être utilisé n’importe quel nombre de fois dans un composant parent, et qui crée des éléments de liste (<li>...</li>
) pour une liste HTML (<ul>...</ul>
ou <ol>...</ol>
).
Chaque instance de composant ListItem2
appelle la fonction assignDotNetHelper
JS dans OnAfterRenderAsync
avec une référence d’élément (premier élément <span>
de l’élément de liste) et l’instance de composant en tant que DotNetObjectReference.
Lorsqu’un <span>
de message d’un composant ListItem2
est sélectionné, interopCall
est appelé en passant l’élément <span>
en tant que 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 deuxième <span>
est mise à jour. Si StateHasChanged
n’est pas appelé, Blazor n’a aucun moyen de savoir que l’interface utilisateur doit être mise à jour lorsque la méthode est appelée.
La DotNetObjectReference est supprimée lorsque le composant est supprimé.
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 void 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)
{
await module.DisposeAsync();
}
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 void 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)
{
await module.DisposeAsync();
}
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 comprend 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 s’applique uniquement 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 interop JS doivent être asynchrones car ils sont envoyés via une connexion réseau.
Si vous savez avec certitude que votre composant s'exécute uniquement sur WebAssembly, vous pouvez choisir d'effectuer des appels interop synchrones JS. 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
à la place de DotNet.invokeMethodAsync
.
Les appels synchrones fonctionnent si :
Emplacement JavaScript
Chargez le code JavaScript (JS) en utilisant une des approches décrites par l’article sur l’emplacement de 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.
Avertissement
Placez une balise <script>
dans un fichier de composant (.razor
) uniquement si vous avez l’assurance que le composant adoptera le rendu statique côté serveur (SSR statique), car la balise <script>
ne peut pas être mise à jour dynamiquement.
Avertissement
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 sendByteArray
JS. La fonction est appelée statiquement, en incluant le paramètre de nom d’assembly dans l’appel invokeMethodAsync
, par un bouton du 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>
Remarque
Pour obtenir une aide générale sur l’emplacement deJS et nos recommandations pour les applications de production, consultez Emplacement de JavaScript dans les applications Blazor ASP.NET Core.
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)
{
await module.DisposeAsync();
}
}
}
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)
{
await module.DisposeAsync();
}
}
}
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 plus d’informations sur l’utilisation d’un tableau d’octets lors de l’appel de JavaScript à partir de .NET, consultez Appeler des fonctions JavaScript à partir de méthodes .NET dans ASP.NET Core Blazor.
Diffuser en continu de JavaScript vers .NET
Blazor prend en charge la diffusion en continu de données directement de JavaScript vers .NET. Les flux sont demandés à l’aide de l’interface Microsoft.JSInterop.IJSStreamReference
.
Microsoft.JSInterop.IJSStreamReference.OpenReadStreamAsync
retourne un Stream et utilise les paramètres suivants :
maxAllowedSize
: nombre maximal d’octets autorisé pour l’opération de lecture à partir de JavaScript, 512 000 octets par défaut si non spécifié.cancellationToken
: CancellationToken pour 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 :
JS
est un instance IJSRuntime injectée. IJSRuntime est inscrit par le framework Blazor.- Le
dataReferenceStream
est écrit sur le disque (file.txt
) au chemin du dossier temporaire de l’utilisateur actuel (GetTempPath).
Appeler des fonctions JavaScript à partir de méthodes .NET dans ASP.NET Core Blazor couvre l’opération inverse, la diffusion en continu de .NET vers JavaScript à l’aide d’une DotNetStreamReference.
Chargements de fichiers ASP.NET Core Blazor explique comment charger un fichier dans Blazor. Pour obtenir un exemple de formulaire qui diffuse en continu des données <textarea>
dans un composant côté serveur, consultez Résoudre les problèmes liés aux formulaires Blazor ASP.NET Core.
JavaScript [JSImport]
/[JSExport]
interop
Cette section s’applique aux composants côté client.
En guise d’alternative à l’interaction avec JavaScript (JS) dans les composants côté client à l’aide du mécanisme d’interopérabilité JS de Blazor basé sur l’interface IJSRuntime, une API d’interopérabilité JS[JSImport]
/[JSExport]
est disponible pour les applications ciblant .NET 7 ou version ultérieure.
Pour plus d’informations, consultez Interopérabilité JSImport/JSExport JavaScript 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 à partir de JS, comme décrit dans cet article, disposez d’un DotNetObjectReference créé à partir de .NET ou de JS pour éviter la fuite 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 identificateur sur le 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
(branchedotnet/AspNetCore
du dépôt GitHubmain
) : la branchemain
représente le développement actuel de l’unité de produit pour la prochaine version d’ASP.NET Core. Pour sélectionner la branche d’une autre version (par exemple,release/5.0
), utilisez la liste déroulante Changer de branche ou d’étiquette pour sélectionner la branche. - Interaction avec le DOM
- Dépôt GitHub d’exemples Blazor (
dotnet/blazor-samples
) (Comment télécharger) - Gérer les erreurs dans les applications ASP.NET Core Blazor (section interopérabilité JavaScript)
- Atténuation des menaces : méthodes .NET appelées à partir du navigateur