Chiamare metodi .NET da funzioni JavaScript in ASP.NET Core Blazor
Nota
Questa non è la versione più recente di questo articolo. Per la versione corrente, vedere la versione .NET 9 di questo articolo.
Avviso
Questa versione di ASP.NET Core non è più supportata. Per altre informazioni, vedere i criteri di supporto di .NET e .NET Core. Per la versione corrente, vedere la versione .NET 9 di questo articolo.
Importante
Queste informazioni si riferiscono a un prodotto non definitive che può essere modificato in modo sostanziale prima che venga rilasciato commercialmente. Microsoft non riconosce alcuna garanzia, espressa o implicita, in merito alle informazioni qui fornite.
Per la versione corrente, vedere la versione .NET 9 di questo articolo.
Questo articolo illustra come richiamare i metodi .NET da JavaScript (JS).
Per informazioni su come chiamare JS le funzioni da .NET, vedere Chiamare le funzioni JavaScript dai metodi .NET in ASP.NET Core Blazor.
Richiamare un metodo .NET statico
Per richiamare un metodo .NET statico da JavaScript (JS), usare le JS funzioni:
DotNet.invokeMethodAsync
(scelta consigliata): asincrona per i componenti lato server e lato client.DotNet.invokeMethod
: sincrono solo per i componenti lato client.
Passare il nome dell'assembly contenente il metodo , l'identificatore del metodo .NET statico ed eventuali argomenti.
Nell'esempio seguente :
- Il
{ASSEMBLY NAME}
segnaposto è il nome dell'assembly dell'app. - Il
{.NET METHOD ID}
segnaposto è l'identificatore del metodo .NET. - Il
{ARGUMENTS}
segnaposto è un argomento facoltativo delimitato da virgole da passare al metodo , ognuno dei quali deve essere serializzabile in JSON.
DotNet.invokeMethodAsync('{ASSEMBLY NAME}', '{.NET METHOD ID}', {ARGUMENTS});
DotNet.invokeMethodAsync
restituisce un oggetto JS Promise
che rappresenta il risultato dell'operazione. DotNet.invokeMethod
(componenti lato client) restituisce il risultato dell'operazione.
Importante
Per i componenti lato server, è consigliabile usare la funzione asincrona (invokeMethodAsync
) sulla versione sincrona (invokeMethod
).
Il metodo .NET deve essere pubblico, statico e avere l'attributo [JSInvokable]
.
Nell'esempio seguente :
- Il
{<T>}
segnaposto indica il tipo restituito, obbligatorio solo per i metodi che restituiscono un valore. - Il
{.NET METHOD ID}
segnaposto è l'identificatore del metodo.
@code {
[JSInvokable]
public static Task{<T>} {.NET METHOD ID}()
{
...
}
}
Nota
La chiamata di metodi generici aperti non è supportata con metodi .NET statici, ma è supportata con i metodi di istanza. Per altre informazioni, vedere la sezione Chiamare i metodi di classe generica .NET.
Nel componente seguente il ReturnArrayAsync
metodo C# restituisce una int
matrice. L'attributo [JSInvokable]
viene applicato al metodo , che rende il metodo richiamabile da 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 addHandlers
JS funzione aggiunge un click
evento al pulsante. La returnArrayAsync
JS funzione viene assegnata come gestore.
La returnArrayAsync
JS funzione chiama il ReturnArrayAsync
metodo .NET del componente, che registra il risultato nella console degli strumenti di sviluppo Web del browser. BlazorSample
è il nome dell'assembly dell'app.
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 addHandlers
JS funzione aggiunge un click
evento al pulsante. La returnArrayAsync
JS funzione viene assegnata come gestore.
La returnArrayAsync
JS funzione chiama il ReturnArrayAsync
metodo .NET del componente, che registra il risultato nella console degli strumenti di sviluppo Web del browser. BlazorSample
è il nome dell'assembly dell'app.
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'attributo <button>
HTML dell'elemento onclick
è l'assegnazione del gestore eventi javaScript onclick
per l'elaborazione click
degli eventi, non Blazorl'attributo di direttiva di @onclick
. La returnArrayAsync
JS funzione viene assegnata come gestore.
La funzione seguente returnArrayAsync
JS chiama il ReturnArrayAsync
metodo .NET del componente, che registra il risultato nella console degli strumenti di sviluppo Web del browser. BlazorSample
è il nome dell'assembly dell'app.
<script>
window.returnArrayAsync = () => {
DotNet.invokeMethodAsync('BlazorSample', 'ReturnArrayAsync')
.then(data => {
console.log(data);
});
};
</script>
Nota
Per indicazioni generali sulla JS posizione e i suggerimenti per le app di produzione, vedere Posizione JavaScript nelle app ASP.NET CoreBlazor.
Quando il Trigger .NET static method
pulsante è selezionato, l'output della console degli strumenti di sviluppo del browser visualizza i dati della matrice. Il formato dell'output è leggermente diverso tra i browser. L'output seguente mostra il formato usato da Microsoft Edge:
Array(3) [ 11, 12, 13 ]
Passare i dati a un metodo .NET quando si chiama la invokeMethodAsync
funzione passando i dati come argomenti.
Per illustrare il passaggio di dati a .NET, passare una posizione iniziale al ReturnArrayAsync
metodo in cui viene richiamato il metodo in 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>
Il metodo richiamabile ReturnArrayAsync
del componente riceve la posizione iniziale e costruisce la matrice da essa. La matrice viene restituita per la registrazione nella console:
[JSInvokable]
public static Task<int[]> ReturnArrayAsync(int startPosition) =>
Task.FromResult(Enumerable.Range(startPosition, 3).ToArray());
Dopo aver ricompilato l'app e aver aggiornato il browser, l'output seguente viene visualizzato nella console del browser quando il pulsante è selezionato:
Array(3) [ 14, 15, 16 ]
L'identificatore del metodo .NET per la JS chiamata è il nome del metodo .NET, ma è possibile specificare un identificatore diverso usando il costruttore dell'attributo[JSInvokable]
. Nell'esempio seguente è DifferentMethodName
l'identificatore del metodo assegnato per il ReturnArrayAsync
metodo :
[JSInvokable("DifferentMethodName")]
Nella chiamata a DotNet.invokeMethodAsync
(componenti lato server o lato client) o DotNet.invokeMethod
(solo componenti lato client), chiamare DifferentMethodName
per eseguire il ReturnArrayAsync
metodo .NET:
DotNet.invokeMethodAsync('BlazorSample', 'DifferentMethodName');
DotNet.invokeMethod('BlazorSample', 'DifferentMethodName');
(solo componenti lato client)
Nota
L'esempio ReturnArrayAsync
di metodo in questa sezione restituisce il risultato di un oggetto Task senza l'uso di parole chiave e await
C# async
esplicite. I metodi di codifica con async
e await
sono tipici di metodi che usano la await
parola chiave per restituire il valore delle operazioni asincrone.
ReturnArrayAsync
metodo composto con async
parole chiave e await
:
[JSInvokable]
public static async Task<int[]> ReturnArrayAsync() =>
await Task.FromResult(new int[] { 11, 12, 13 });
Per altre informazioni, vedere Programmazione asincrona con async e await nella guida di C#.
Creare riferimenti a oggetti e dati JavaScript da passare a .NET
Chiamare DotNet.createJSObjectReference(jsObject)
per costruire un riferimento a un JS oggetto in modo che possa essere passato a .NET, dove jsObject
viene JS Object
usato per creare il riferimento all'oggetto JS . Nell'esempio seguente viene passato un riferimento all'oggetto non serializzabile window
a .NET, che lo riceve nel ReceiveWindowObject
metodo C# come IJSObjectReference:
DotNet.invokeMethodAsync('{ASSEMBLY NAME}', 'ReceiveWindowObject',
DotNet.createJSObjectReference(window));
[JSInvokable]
public static void ReceiveWindowObject(IJSObjectReference objRef)
{
...
}
Nell'esempio precedente il {ASSEMBLY NAME}
segnaposto è lo spazio dei nomi dell'app.
Nota
L'esempio precedente non richiede l'eliminazione JSObjectReference
di , come riferimento all'oggetto window
non viene mantenuto in JS.
Per mantenere un riferimento a un oggetto JSObjectReference
è necessario eliminarlo per evitare perdite JS di memoria nel client. Nell'esempio seguente viene eseguito il refactoring del codice precedente per acquisire un riferimento a JSObjectReference
, seguito da una chiamata a per DotNet.disposeJSObjectReference()
eliminare il riferimento:
var jsObjectReference = DotNet.createJSObjectReference(window);
DotNet.invokeMethodAsync('{ASSEMBLY NAME}', 'ReceiveWindowObject', jsObjectReference);
DotNet.disposeJSObjectReference(jsObjectReference);
Nell'esempio precedente il {ASSEMBLY NAME}
segnaposto è lo spazio dei nomi dell'app.
Chiamare DotNet.createJSStreamReference(streamReference)
per costruire un JS riferimento al flusso in modo che possa essere passato a .NET, dove streamReference
è una ArrayBuffer
matrice , Blob
o qualsiasi matrice tipizzata, ad esempio Uint8Array
o Float32Array
, usata per creare il riferimento al JS flusso.
Richiamare un metodo .NET di istanza
Per richiamare un metodo .NET dell'istanza da JavaScript (JS):
Passare l'istanza .NET per riferimento a JS eseguendo il wrapping dell'istanza in un DotNetObjectReference oggetto e chiamandola Create .
Richiamare un metodo di istanza .NET usando JS
invokeMethodAsync
(scelta consigliata) oinvokeMethod
(solo componenti lato client) dall'oggetto passato DotNetObjectReference. Passare l'identificatore del metodo .NET dell'istanza e qualsiasi argomento. L'istanza di .NET può anche essere passata come argomento quando si richiamano altri metodi .NET da JS.Nell'esempio seguente :
dotNetHelper
è un oggetto DotNetObjectReference.- Il
{.NET METHOD ID}
segnaposto è l'identificatore del metodo .NET. - Il
{ARGUMENTS}
segnaposto è un argomento facoltativo delimitato da virgole da passare al metodo , ognuno dei quali deve essere serializzabile in JSON.
dotNetHelper.invokeMethodAsync('{.NET METHOD ID}', {ARGUMENTS});
Nota
invokeMethodAsync
einvokeMethod
non accettano un parametro del nome dell'assembly quando si richiama un metodo di istanza.invokeMethodAsync
restituisce un oggetto JSPromise
che rappresenta il risultato dell'operazione.invokeMethod
(solo componenti lato client) restituisce il risultato dell'operazione.Importante
Per i componenti lato server, è consigliabile usare la funzione asincrona (
invokeMethodAsync
) sulla versione sincrona (invokeMethod
).Eliminare l'oggetto DotNetObjectReference.
Le sezioni seguenti di questo articolo illustrano diversi approcci per richiamare un metodo .NET di istanza:
Evitare di tagliare i metodi JavaScript-invokable .NET
Questa sezione si applica alle app sul lato client con compilazione anticipata (AOT) e ricollegamento del runtime abilitato.
Diversi esempi nelle sezioni seguenti sono basati su un approccio all'istanza di classe, in cui il metodo .NET richiamabile JavaScript contrassegnato con l'attributo [JSInvokable]
è un membro di una classe che non è un Razor componente. Quando tali metodi .NET si trovano in un Razor componente, sono protetti dal ricollegamento/taglio in fase di esecuzione. Per proteggere i metodi .NET dal taglio all'esterno dei Razor componenti, implementare i metodi con l'attributo DynamicDependency
nel costruttore della classe, come illustrato nell'esempio seguente:
using System.Diagnostics.CodeAnalysis;
using Microsoft.JSInterop;
public class ExampleClass {
[DynamicDependency(nameof(ExampleJSInvokableMethod))]
public ExampleClass()
{
}
[JSInvokable]
public string ExampleJSInvokableMethod()
{
...
}
}
Per altre informazioni, vedere Preparare le librerie .NET per il taglio: DynamicDependency.
Passare un DotNetObjectReference
oggetto a una singola funzione JavaScript
L'esempio in questa sezione illustra come passare un DotNetObjectReference oggetto a una singola funzione JavaScript (JS).
La funzione seguente sayHello1
JS riceve un e DotNetObjectReference chiama invokeMethodAsync
per chiamare il GetHelloMessage
metodo .NET di un componente:
<script>
window.sayHello1 = (dotNetHelper) => {
return dotNetHelper.invokeMethodAsync('GetHelloMessage');
};
</script>
Nota
Per indicazioni generali sulla JS posizione e i suggerimenti per le app di produzione, vedere Posizione JavaScript nelle app ASP.NET CoreBlazor.
Nell'esempio precedente il nome dotNetHelper
della variabile è arbitrario e può essere modificato in qualsiasi nome preferito.
Per il componente seguente:
- Il componente ha un JSmetodo .NET richiamabile denominato
GetHelloMessage
. - Quando il
Trigger .NET instance method
pulsante è selezionato, la JS funzionesayHello1
viene chiamata con .DotNetObjectReference sayHello1
:- Chiama
GetHelloMessage
e riceve il risultato del messaggio. - Restituisce il risultato del messaggio al metodo chiamante
TriggerDotNetInstanceMethod
.
- Chiama
- Il messaggio restituito da
sayHello1
inresult
viene visualizzato all'utente. - Per evitare una perdita di memoria e consentire l'operazione di Garbage Collection, il riferimento all'oggetto .NET creato da DotNetObjectReference viene eliminato nel
Dispose
metodo .
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();
}
}
Nell'esempio precedente il nome dotNetHelper
della variabile è arbitrario e può essere modificato in qualsiasi nome preferito.
Usare le indicazioni seguenti per passare argomenti a un metodo di istanza:
Aggiungere parametri alla chiamata al metodo .NET. Nell'esempio seguente viene passato un nome al metodo . Aggiungere altri parametri all'elenco in base alle esigenze.
<script>
window.sayHello2 = (dotNetHelper, name) => {
return dotNetHelper.invokeMethodAsync('GetHelloMessage', name);
};
</script>
Nell'esempio precedente il nome dotNetHelper
della variabile è arbitrario e può essere modificato in qualsiasi nome preferito.
Specificare l'elenco di parametri al metodo .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();
}
}
Nell'esempio precedente il nome dotNetHelper
della variabile è arbitrario e può essere modificato in qualsiasi nome preferito.
Passare a DotNetObjectReference
una classe con più funzioni JavaScript
L'esempio in questa sezione illustra come passare un DotNetObjectReference oggetto a una classe JavaScript (JS) con più funzioni.
Creare e passare un DotNetObjectReference oggetto dal metodo del OnAfterRenderAsync
ciclo di vita a una JS classe per più funzioni da usare. Assicurarsi che il codice .NET elimini , DotNetObjectReferencecome illustrato nell'esempio seguente.
Nel componente seguente i pulsanti chiamano le Trigger JS function
funzioni impostando la JSonclick
proprietà , non Blazorl'attributo di direttiva.@onclick
JS
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();
}
}
Nell'esempio precedente:
JS
è un'istanza inserita IJSRuntime . IJSRuntime viene registrato dal Blazor framework.- Il nome
dotNetHelper
della variabile è arbitrario e può essere modificato in qualsiasi nome preferito. - Il componente deve eliminare in modo esplicito l'oggetto per consentire l'operazione DotNetObjectReference di Garbage Collection e impedire una perdita di memoria.
- JSDisconnectedException viene intrappolato durante l'eliminazione del modulo nel caso Blazorin cui il circuito venga SignalR perso. Se il codice precedente viene usato in un'appBlazor WebAssembly, non c'è alcuna SignalR connessione da perdere, quindi è possibile rimuovere il
catch
try
-blocco e lasciare la riga che elimina il modulo ().await module.DisposeAsync();
Per altre informazioni, vedere ASP.NET Core JavaScript interoperabilità (interoperabilità).For more information, see ASP.NET Core Blazor JavaScript interoperability (JS interop).
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);
}
Nell'esempio precedente il nome dotNetHelper
della variabile è arbitrario e può essere modificato in qualsiasi nome preferito.
@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();
}
}
Nell'esempio precedente:
JS
è un'istanza inserita IJSRuntime . IJSRuntime viene registrato dal Blazor framework.- Il nome
dotNetHelper
della variabile è arbitrario e può essere modificato in qualsiasi nome preferito. - Il componente deve eliminare in modo esplicito l'oggetto per consentire l'operazione DotNetObjectReference di Garbage Collection e impedire una perdita di memoria.
<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>
Nell'esempio precedente:
- La
GreetingHelpers
classe viene aggiunta all'oggettowindow
per definire globalmente la classe , che consente Blazor di individuare la classe per JS l'interoperabilità. - Il nome
dotNetHelper
della variabile è arbitrario e può essere modificato in qualsiasi nome preferito.
Nota
Per indicazioni generali sulla JS posizione e i suggerimenti per le app di produzione, vedere Posizione JavaScript nelle app ASP.NET CoreBlazor.
Chiamare i metodi di classe generica .NET
Le funzioni JavaScript (JS) possono chiamare metodi di classe generica .NET, in cui una JS funzione chiama un metodo .NET di una classe generica.
Nella classe di tipo generico seguente (GenericType<TValue>
):
- La classe ha un singolo parametro di tipo (
TValue
) con una singola proprietà genericaValue
. - La classe ha due metodi non generici contrassegnati con l'attributo
[JSInvokable]
, ognuno con un parametro di tipo generico denominatonewValue
:Update
Aggiorna in modo sincrono il valore diValue
danewValue
.UpdateAsync
aggiorna in modo asincrono il valore di danewValue
dopo la creazione diValue
un'attività awaitable con Task.Yield che restituisce in modo asincrono il contesto corrente quando è atteso.
- Ognuno dei metodi della classe scrive il tipo di
TValue
e il valore diValue
nella console. La scrittura nella console è solo a scopo dimostrativo. Le app di produzione in genere evitano di scrivere nella console a favore della registrazione delle app. Per altre informazioni, vedere registrazione e registrazione di ASP.NET Core Blazor in .NET Core e ASP.NET Core.
Nota
I tipi e i metodi generici aperti non specificano tipi per i segnaposto dei tipi. Al contrario, i generics chiusi forniscono tipi per tutti i segnaposto di tipo. Gli esempi in questa sezione illustrano generics chiusi, ma è supportato richiamare JS i metodi di istanza di interoperabilità con generics aperti. L'uso di generics aperti non è supportato per le chiamate al metodo .NET statico, descritte in precedenza in questo articolo.
Per altre informazioni, vedere gli articoli seguenti:
- Classi e metodi generici (documentazione di C#)
- Classi generiche (Guida per programmatori C#)
- Generics in .NET (documentazione di .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}");
}
}
Nella funzione seguente invokeMethodsAsync
:
- I metodi e
UpdateAsync
dellaUpdate
classe di tipo generico vengono chiamati con argomenti che rappresentano stringhe e numeri. - I componenti lato client supportano la chiamata sincrona dei metodi .NET con
invokeMethod
.syncInterop
riceve un valore booleano che indica se l'interoperabilità JS si verifica nel client. QuandosyncInterop
ètrue
,invokeMethod
viene chiamato in modo sicuro. Se il valore disyncInterop
èfalse
, viene chiamata solo la funzioneinvokeMethodAsync
asincrona perché l'interoperabilità JS viene eseguita in un componente lato server. - A scopo dimostrativo, la DotNetObjectReference chiamata di funzione (
invokeMethod
oinvokeMethodAsync
), il metodo .NET denominato (Update
oUpdateAsync
) e l'argomento vengono scritti nella console. Gli argomenti usano un numero casuale per consentire la corrispondenza della JS chiamata di funzione alla chiamata al metodo .NET (scritto anche nella console sul lato .NET). Il codice di produzione in genere non scrive nella console, nel client o nel server. Le app di produzione si basano in genere sulla registrazione delle app. Per altre informazioni, vedere registrazione e registrazione di ASP.NET Core Blazor in .NET Core e 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>
Nota
Per indicazioni generali sulla JS posizione e i suggerimenti per le app di produzione, vedere Posizione JavaScript nelle app ASP.NET CoreBlazor.
Nel componente GenericsExample
seguente:
- La JS funzione
invokeMethodsAsync
viene chiamata quando ilInvoke Interop
pulsante è selezionato. - Vengono creati e passati alla JS funzione una coppia di DotNetObjectReference tipi per le istanze di
GenericType
comestring
e .int
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();
}
}
Nell'esempio precedente è JS
un'istanza inserita IJSRuntime . IJSRuntime viene registrato dal Blazor framework.
Di seguito viene illustrato l'output tipico dell'esempio precedente quando il Invoke Interop
pulsante viene selezionato in un componente lato 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
Se l'esempio precedente viene implementato in un componente lato server, le chiamate sincrone con invokeMethod
vengono evitate. Per i componenti lato server, è consigliabile usare la funzione asincrona (invokeMethodAsync
) sulla versione sincrona (invokeMethod
).
Output tipico di un componente lato server:
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>: stringa 93059
.NET: UpdateAsync: GenericType<System.Int32>: 24652
Gli esempi di output precedenti illustrano che i metodi asincroni vengono eseguiti e completati in un ordine arbitrario, a seconda di diversi fattori, tra cui la pianificazione dei thread e la velocità di esecuzione del metodo. Non è possibile stimare in modo affidabile l'ordine di completamento per le chiamate asincrone ai metodi.
Esempi di istanze di classe
La funzione seguente sayHello1
JS :
- Chiama il
GetHelloMessage
metodo .NET sull'oggetto passato DotNetObjectReference. - Restituisce il messaggio da
GetHelloMessage
alsayHello1
chiamante.
<script>
window.sayHello1 = (dotNetHelper) => {
return dotNetHelper.invokeMethodAsync('GetHelloMessage');
};
</script>
Nota
Per indicazioni generali sulla JS posizione e i suggerimenti per le app di produzione, vedere Posizione JavaScript nelle app ASP.NET CoreBlazor.
Nell'esempio precedente il nome dotNetHelper
della variabile è arbitrario e può essere modificato in qualsiasi nome preferito.
La classe seguente HelloHelper
include un JSmetodo .NET richiamabile denominato GetHelloMessage
. Quando HelloHelper
viene creato, il nome nella Name
proprietà viene usato per restituire un messaggio da 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}!";
}
Il CallHelloHelperGetHelloMessage
metodo nella classe seguente JsInteropClasses3
richiama la JS funzione sayHello1
con una nuova istanza di 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);
}
}
Per evitare una perdita di memoria e consentire l'operazione di Garbage Collection, il riferimento all'oggetto .NET creato da DotNetObjectReference viene eliminato quando il riferimento all'oggetto esce dall'ambito con using var
la sintassi.
Quando il Trigger .NET instance method
pulsante viene selezionato nel componente seguente, JsInteropClasses3.CallHelloHelperGetHelloMessage
viene chiamato con il valore di 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'immagine seguente mostra il componente di cui è stato eseguito il rendering con il nome Amy Pond
nel Name
campo . Dopo aver selezionato il pulsante, Hello, Amy Pond!
viene visualizzato nell'interfaccia utente:
Anche il JsInteropClasses3
modello precedente illustrato nella classe può essere implementato interamente in un componente.
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);
}
}
Per evitare una perdita di memoria e consentire l'operazione di Garbage Collection, il riferimento all'oggetto .NET creato da DotNetObjectReference viene eliminato quando il riferimento all'oggetto esce dall'ambito con using var
la sintassi.
L'output visualizzato dal componente è Hello, Amy Pond!
quando il nome Amy Pond
viene specificato nel name
campo .
Nel componente precedente il riferimento all'oggetto .NET viene eliminato. Se una classe o un componente non elimina DotNetObjectReference, eliminarlo dal client chiamando dispose
sull'oggetto passato DotNetObjectReference:
window.{JS FUNCTION NAME} = (dotNetHelper) => {
dotNetHelper.invokeMethodAsync('{.NET METHOD ID}');
dotNetHelper.dispose();
}
Nell'esempio precedente:
- Il
{JS FUNCTION NAME}
segnaposto è il JS nome della funzione. - Il nome
dotNetHelper
della variabile è arbitrario e può essere modificato in qualsiasi nome preferito. - Il
{.NET METHOD ID}
segnaposto è l'identificatore del metodo .NET.
Classe helper del metodo .NET dell'istanza del componente
Una classe helper può richiamare un metodo di istanza .NET come Action. Le classi helper sono utili negli scenari in cui l'uso di metodi .NET statici non è applicabile:
- Quando viene eseguito il rendering di più componenti dello stesso tipo nella stessa pagina.
- Nelle app lato server con più utenti contemporaneamente usando lo stesso componente.
Nell'esempio seguente :
- Il componente contiene diversi
ListItem1
componenti. - Ogni
ListItem1
componente è costituito da un messaggio e da un pulsante. - Quando viene selezionato un
ListItem1
pulsante componente, il metodo diUpdateMessage
taleListItem1
metodo modifica il testo dell'elemento di elenco e nasconde il pulsante.
La classe seguente MessageUpdateInvokeHelper
gestisce un JSmetodo .NET richiamabile, UpdateMessageCaller
, per richiamare l'oggetto specificato quando viene creata un'istanza Action della 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 funzione seguente updateMessageCaller
JS richiama il UpdateMessageCaller
metodo .NET.
<script>
window.updateMessageCaller = (dotNetHelper) => {
dotNetHelper.invokeMethodAsync('UpdateMessageCaller');
dotNetHelper.dispose();
}
</script>
Nota
Per indicazioni generali sulla JS posizione e i suggerimenti per le app di produzione, vedere Posizione JavaScript nelle app ASP.NET CoreBlazor.
Nell'esempio precedente il nome dotNetHelper
della variabile è arbitrario e può essere modificato in qualsiasi nome preferito.
Il componente seguente ListItem1
è un componente condiviso che può essere usato un numero qualsiasi di volte in un componente padre e crea voci di elenco (<li>...</li>
) per un elenco HTML (<ul>...</ul>
o <ol>...</ol>
). Ogni ListItem1
istanza del componente stabilisce un'istanza di MessageUpdateInvokeHelper
con un Action oggetto impostato sul relativo UpdateMessage
metodo.
Quando si seleziona il pulsante di un ListItem1
componente, updateMessageCaller
viene richiamato con un creato DotNetObjectReference per l'istanzaMessageUpdateInvokeHelper
.InteropCall
In questo modo il framework può chiamare UpdateMessageCaller
l'istanza di tale ListItem1
MessageUpdateInvokeHelper
istanza. L'oggetto passato DotNetObjectReference viene eliminato in 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
viene chiamato per aggiornare l'interfaccia utente quando message
è impostato in UpdateMessage
. Se StateHasChanged
non viene chiamato, Blazor non è possibile sapere che l'interfaccia utente deve essere aggiornata quando Action viene richiamato .
Il componente padre seguente include quattro voci di elenco, ognuna delle quali è un'istanza del ListItem1
componente.
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'immagine seguente mostra il componente padre di cui è stato eseguito il rendering dopo aver selezionato il secondo InteropCall
pulsante:
- Il secondo
ListItem1
componente ha visualizzato ilUpdateMessage Called!
messaggio. - Il
InteropCall
pulsante per il secondoListItem1
componente non è visibile perché la proprietà CSSdisplay
del pulsante è impostata sunone
.
Metodo .NET dell'istanza del componente chiamato da DotNetObjectReference
assegnato a una proprietà dell'elemento
L'assegnazione di un DotNetObjectReference oggetto a una proprietà di un elemento HTML consente di chiamare metodi .NET in un'istanza del componente:
- Viene acquisito un riferimento a un elemento (ElementReference).
- Nel metodo del
OnAfterRender{Async}
componente viene richiamata una funzione JavaScript (JS) con il riferimento all'elemento e l'istanza del componente come DotNetObjectReference. La JS funzione associa l'oggetto DotNetObjectReference all'elemento in una proprietà . - Quando viene richiamato un evento di elemento in JS (ad esempio,
onclick
), l'elemento associato DotNetObjectReference viene usato per chiamare un metodo .NET.
Analogamente all'approccio descritto nella sezione Classe helper del metodo .NET dell'istanza del componente, questo approccio è utile negli scenari in cui l'uso di metodi .NET statici non è applicabile:
- Quando viene eseguito il rendering di più componenti dello stesso tipo nella stessa pagina.
- Nelle app lato server con più utenti contemporaneamente usando lo stesso componente.
- Il metodo .NET viene richiamato da un JS evento (ad esempio,
onclick
), non da un Blazor evento (ad esempio,@onclick
).
Nell'esempio seguente :
- Il componente contiene diversi
ListItem2
componenti, ovvero un componente condiviso. - Ogni
ListItem2
componente è costituito da un messaggio<span>
di elemento di elenco e un secondo<span>
con unadisplay
proprietà CSS impostata suinline-block
per la visualizzazione. - Quando viene selezionato un
ListItem2
elemento di elenco dei componenti, taleUpdateMessage
ListItem2
metodo modifica il testo dell'elemento di elenco nel primo<span>
e nasconde il secondo<span>
impostando la relativadisplay
proprietà sunone
.
La funzione seguente assignDotNetHelper
JS assegna a DotNetObjectReference un elemento in una proprietà denominata dotNetHelper
. La funzione seguente interopCall
JS usa per DotNetObjectReference l'elemento passato per richiamare un metodo .NET denominato 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>
Nota
Per indicazioni generali sulla JS posizione e i suggerimenti per le app di produzione, vedere Posizione JavaScript nelle app ASP.NET CoreBlazor.
Nell'esempio precedente il nome dotNetHelper
della variabile è arbitrario e può essere modificato in qualsiasi nome preferito.
Il componente seguente ListItem2
è un componente condiviso che può essere usato un numero qualsiasi di volte in un componente padre e crea voci di elenco (<li>...</li>
) per un elenco HTML (<ul>...</ul>
o <ol>...</ol>
).
Ogni ListItem2
istanza del componente richiama la assignDotNetHelper
JS funzione in OnAfterRenderAsync
con un riferimento all'elemento (il primo <span>
elemento dell'elemento di elenco) e l'istanza del componente come .DotNetObjectReference
Quando viene selezionato il messaggio di un ListItem2
componente, interopCall
viene richiamato passando l'elemento <span>
come parametro (this
), che richiama il UpdateMessage
metodo .<span>
NET. StateHasChanged
In UpdateMessage
viene chiamato per aggiornare l'interfaccia utente quando message
è impostato e la display
proprietà del secondo <span>
viene aggiornata. Se StateHasChanged
non viene chiamato, Blazor non è possibile sapere che l'interfaccia utente deve essere aggiornata quando viene richiamato il metodo.
L'oggetto DotNetObjectReference viene eliminato quando il componente viene eliminato.
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();
}
Il componente padre seguente include quattro voci di elenco, ognuna delle quali è un'istanza del ListItem2
componente.
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>
Interoperabilità sincrona JS nei componenti lato client
Questa sezione si applica solo ai componenti lato client.
JS le chiamate di interoperabilità sono asincrone, indipendentemente dal fatto che il codice chiamato sia sincrono o asincrono. Le chiamate sono asincrone per garantire che i componenti siano compatibili tra le modalità di rendering lato server e lato client. Nel server tutte le JS chiamate di interoperabilità devono essere asincrone perché vengono inviate tramite una connessione di rete.
Se si è certi che il componente viene eseguito solo in WebAssembly, è possibile scegliere di effettuare chiamate di interoperabilità sincrone JS . Questo comporta un sovraccarico leggermente inferiore rispetto all'esecuzione di chiamate asincrone e può comportare un minor numero di cicli di rendering perché non esiste uno stato intermedio in attesa dei risultati.
Per eseguire una chiamata sincrona da JavaScript a .NET in un componente lato client, usare DotNet.invokeMethod
anziché DotNet.invokeMethodAsync
.
Le chiamate sincrone funzionano se:
Percorso JavaScript
Caricare il codice JavaScript (JS) usando uno degli approcci descritti dall'articolo sul percorso JavaScript:
- Caricare uno script nel markup
<head>
(generalmente non consigliato) - Caricare uno script nel markup
<body>
- Caricare uno script da un file JavaScript esterno (
.js
) con il percorso condiviso con un componente - Caricare uno script da un file JavaScript esterno (
.js
) - Inserire uno script prima o dopo Blazor l'avvio
L'uso dei JS moduli da caricare JS è descritto in questo articolo nella sezione Isolamento JavaScript nei moduli JavaScript.
Avviso
Inserire un <script>
tag in un file di componente (.razor
) solo se il componente deve adottare il rendering statico lato server (SSR statico) perché il <script>
tag non può essere aggiornato in modo dinamico.
Avviso
Non inserire un <script>
tag in un file di componente (.razor
) perché il <script>
tag non può essere aggiornato in modo dinamico.
Isolamento di JavaScript nei moduli di JavaScript
Blazor consente l'isolamento di JavaScript (JS) nei moduli JavaScript standard (specifica ECMAScript). Il caricamento del modulo JavaScript funziona allo stesso modo Blazor in quanto funziona per altri tipi di app Web e puoi personalizzare il modo in cui i moduli vengono definiti nell'app. Per una guida su come usare i moduli JavaScript, vedere Documentazione Web MDN: moduli JavaScript.
L'isolamento di JS offre i vantaggi seguenti:
- Il codice JS importato non inquina più lo spazio dei nomi globale.
- I consumer di una libreria e dei componenti non devono importare il codice JS correlato.
Per altre informazioni, vedere Chiamare funzioni JavaScript da metodi .NET in ASP.NET Core Blazor.
L'importazione dinamica con l'operatore import()
è supportata con ASP.NET Core e Blazor:
if ({CONDITION}) import("/additionalModule.js");
Nell'esempio precedente il {CONDITION}
segnaposto rappresenta un controllo condizionale per determinare se il modulo deve essere caricato.
Per la compatibilità del browser, vedere È possibile usare i moduli JavaScript: importazione dinamica.
Evitare riferimenti a oggetti circolari
Gli oggetti che contengono riferimenti circolari non possono essere serializzati nel client per:
- Chiamate al metodo .NET.
- Chiamate al metodo JavaScript da C# quando il tipo restituito ha riferimenti circolari.
Supporto della matrice di byte
Blazor supporta l'interoperabilità JavaScript (JS) della matrice di byte ottimizzata che evita la codifica/decodifica delle matrici di byte in Base64. Nell'esempio seguente viene JS usata l'interoperabilità per passare una matrice di byte a .NET.
Specificare una sendByteArray
JS funzione. La funzione viene chiamata in modo statico, che include il parametro del nome dell'assembly nella invokeMethodAsync
chiamata, da un pulsante nel componente e non restituisce un valore:
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>
Nota
Per indicazioni generali sulla JS posizione e i suggerimenti per le app di produzione, vedere Posizione JavaScript nelle app ASP.NET CoreBlazor.
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));
}
}
Per informazioni sull'uso di una matrice di byte quando si chiama JavaScript da .NET, vedere Chiamare le funzioni JavaScript dai metodi .NET in ASP.NET Core Blazor.
Trasmettere da JavaScript a .NET
Blazor supporta lo streaming di dati direttamente da JavaScript a .NET. I flussi vengono richiesti tramite l'interfaccia Microsoft.JSInterop.IJSStreamReference
.
Microsoft.JSInterop.IJSStreamReference.OpenReadStreamAsync
restituisce un Stream oggetto e utilizza i parametri seguenti:
maxAllowedSize
: numero massimo di byte consentiti per l'operazione di lettura da JavaScript, che per impostazione predefinita è 512.000 byte se non specificato.cancellationToken
: oggetto CancellationToken per annullare la lettura.
In JavaScript:
function streamToDotNet() {
return new Uint8Array(10000000);
}
Nel codice 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);
Nell'esempio precedente:
JS
è un'istanza inserita IJSRuntime . IJSRuntime viene registrato dal Blazor framework.dataReferenceStream
Viene scritto su disco (file.txt
) nel percorso temporaneo dell'utente corrente (GetTempPath).
Chiamare le funzioni JavaScript dai metodi .NET in ASP.NET Core Blazor illustra l'operazione inversa, il flusso da .NET a JavaScript usando .DotNetStreamReference
ASP.NET caricamenti di file di base Blazor illustra come caricare un file in Blazor. Per un esempio di moduli che trasmette i <textarea>
dati in un componente lato server, vedere Risolvere i problemi relativi ai moduli ASP.NET CoreBlazor.
Interoperabilità JavaScript [JSImport]
/[JSExport]
Questa sezione si applica ai componenti lato client.
In alternativa all'interazione con JavaScript (JS) nei componenti lato client usando Blazoril meccanismo di JS interoperabilità basato sull'interfaccia IJSRuntime , un'API JS[JSImport]
/[JSExport]
di interoperabilità è disponibile per le app destinate a .NET 7 o versione successiva.
Per altre informazioni, vedere Interoperabilità JSImport/JSExport JavaScript con ASP.NET Core Blazor.
Eliminazione dei riferimenti agli oggetti di interoperabilità JavaScript
Esempi in tutti gli articoli di interoperabilità JavaScript (JS) illustrano i modelli di eliminazione di oggetti tipici:
Quando si chiama .NET da JS, come descritto in questo articolo, eliminare un creato DotNetObjectReference da .NET o da JS per evitare perdite di memoria .NET.
Quando si chiama JS da .NET, come descritto in Chiamare funzioni JavaScript da metodi .NET in ASP.NET CoreBlazor, eliminare qualsiasi creatoIJSInProcessObjectReference//
JSObjectReference
IJSObjectReferenceda .NET o da JS per evitare perdite di JS memoria.
JS I riferimenti agli oggetti di interoperabilità vengono implementati come mappa con chiave da un identificatore sul lato della JS chiamata di interoperabilità che crea il riferimento. Quando l'eliminazione di oggetti viene avviata da .NET o JS lato, Blazor rimuove la voce dalla mappa e l'oggetto può essere sottoposto a Garbage Collection purché non sia presente alcun altro riferimento sicuro all'oggetto.
Eliminare sempre gli oggetti creati sul lato .NET per evitare perdite di memoria gestita .NET.
Attività di pulizia DOM durante l'eliminazione dei componenti
Per altre informazioni, vedere ASP.NET Core JavaScript interoperabilità (interoperabilità).For more information, see ASP.NET Core Blazor JavaScript interoperability (JS interop).
Chiamate di interoperabilità JavaScript senza circuito
Per altre informazioni, vedere ASP.NET Core JavaScript interoperabilità (interoperabilità).For more information, see ASP.NET Core Blazor JavaScript interoperability (JS interop).
Risorse aggiuntive
- Chiamare funzioni JavaScript da metodi .NET in ASP.NET Core Blazor
InteropComponent.razor
esempio (dotnet/AspNetCore
ramo del repositorymain
GitHub): ilmain
ramo rappresenta lo sviluppo corrente dell'unità prodotto per la versione successiva di ASP.NET Core. Per selezionare il ramo per una versione diversa,release/{VERSION}
ad esempio , in cui il{VERSION}
segnaposto è la versione di rilascio, usare l'elenco a discesa Cambia rami o tag per selezionare il ramo. Per un ramo che non esiste più, usare la scheda Tag per trovare l'API , ad esempiov7.0.0
.- Interazione con il DOM
- Blazorrepository GitHub di esempi () (
dotnet/blazor-samples
come scaricare) - Gestire gli errori nelle app core ASP.NET Blazor (sezione Interoperabilità JavaScript)
- Mitigazione delle minacce: metodi .NET richiamati dal browser