Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Note
Questa non è la versione più recente di questo articolo. Per la versione corrente, vedere la versione .NET 10 di questo articolo.
Warning
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 10 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.
Note
Sono supportati i tipi di unione C#.
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
{PACKAGE ID/ASSEMBLY NAME}segnaposto è l'ID pacchetto del progetto (<PackageId>nel file di progetto) per una libreria o un nome di assembly per un'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('{PACKAGE ID/ASSEMBLY NAME}', '{.NET METHOD ID}', {ARGUMENTS});
DotNet.invokeMethodAsync restituisce un oggetto JS Promise che rappresenta il risultato dell'operazione.
DotNet.invokeMethod (componenti lato client) restituiscono il risultato dell'operazione.
Important
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}()
{
...
}
}
Note
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 addHandlersJS funzione aggiunge un click evento al pulsante. La returnArrayAsyncJS funzione viene assegnata come gestore.
La returnArrayAsyncJS 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 addHandlersJS funzione aggiunge un click evento al pulsante. La returnArrayAsyncJS funzione viene assegnata come gestore.
La returnArrayAsyncJS 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 HTML onclick dell'elemento <button> corrisponde all'assegnazione del gestore di eventi onclick di JavaScript per l'elaborazione degli eventi click, non all'attributo di direttiva @onclick di Blazor. La returnArrayAsyncJS funzione viene assegnata come gestore.
La funzione seguente returnArrayAsyncJS 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>
Note
Per indicazioni generali sulla posizione di JS e sulle nostre raccomandazioni per le app di produzione, vedere Posizione di JavaScript nelle app di ASP.NET Core Blazor.
Quando si seleziona il pulsante Trigger .NET static method, la console degli strumenti per sviluppatori del browser mostra i dati dell'array. 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 funzione invokeMethodAsync, passando i dati come argomenti.
Per dimostrare il passaggio di dati a .NET, passare una posizione iniziale al metodo ReturnArrayAsync nel punto in cui il metodo viene invocato 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)
Note
L'esempio di metodo ReturnArrayAsync in questa sezione restituisce il risultato di un Task senza usare in modo esplicito le parole chiave C# async e await. 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 creare un riferimento a un oggetto JS in modo che possa essere passato a .NET, dove jsObject è il 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('{PACKAGE ID/ASSEMBLY NAME}', 'ReceiveWindowObject',
DotNet.createJSObjectReference(window));
[JSInvokable]
public static void ReceiveWindowObject(IJSObjectReference objRef)
{
...
}
Nell'esempio precedente il {PACKAGE ID/ASSEMBLY NAME} segnaposto è l'ID del pacchetto del progetto (<PackageId> nel file di progetto) per una libreria o un nome di assembly per un'app.
Note
L'esempio precedente non richiede l'eliminazione di JSObjectReference, poiché in JS non viene mantenuto alcun riferimento all'oggetto window.
Per mantenere un riferimento a un oggetto JSObjectReference è necessario eliminarlo per evitare perdite JS di memoria nel client. L'esempio seguente sottopone a refactoring il codice precedente per acquisire un riferimento a JSObjectReference, seguito da una chiamata a DotNet.disposeJSObjectReference() per rilasciare il riferimento:
var jsObjectReference = DotNet.createJSObjectReference(window);
DotNet.invokeMethodAsync('{PACKAGE ID/ASSEMBLY NAME}', 'ReceiveWindowObject', jsObjectReference);
DotNet.disposeJSObjectReference(jsObjectReference);
Nell'esempio precedente il {PACKAGE ID/ASSEMBLY NAME} segnaposto è l'ID del pacchetto del progetto (<PackageId> nel file di progetto) per una libreria o un nome di assembly per un'app.
Chiama DotNet.createJSStreamReference(streamReference) per creare un riferimento di flusso JS in modo che possa essere passato a .NET, dove streamReference è un ArrayBufferarray, Blobo qualsiasi array tipizzato, ad esempio Uint8Array o Float32Array, usato per creare il riferimento al flusso JS.
Richiamare un metodo .NET di istanza
Per richiamare un metodo di istanza .NET da JavaScript (JS):
Passa l'istanza .NET per riferimento a JS racchiudendo l'istanza in un oggetto DotNetObjectReference e chiamando Create su di esso.
Richiama un metodo di istanza .NET da JS usando
invokeMethodAsync(consigliato) oinvokeMethod(solo componenti lato client) dall'DotNetObjectReference passato. Passare l'identificatore del metodo .NET dell'istanza e gli eventuali argomenti. L'istanza di .NET può anche essere passata come argomento quando si richiamano altri metodi .NET da JS.Nell'esempio seguente :
-
dotNetHelperè un 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});Note
invokeMethodAsynceinvokeMethodnon accettano un parametro del nome dell'assembly quando si richiama un metodo di istanza.invokeMethodAsyncrestituisce un oggetto JSPromiseche rappresenta il risultato dell'operazione.invokeMethod(solo componenti lato client) restituisce il risultato dell'operazione.Important
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 la rimozione dei metodi .NET invocabili da JavaScript
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 l'ottimizzazione tramite trimming: DynamicDependency.
Passa un DotNetObjectReference a una singola funzione JavaScript
L'esempio in questa sezione illustra come passare un DotNetObjectReference a una specifica funzione JavaScript (JS).
La seguente funzione sayHello1JS riceve un DotNetObjectReference e chiama invokeMethodAsync per chiamare il metodo .NET GetHelloMessage di un componente:
<script>
window.sayHello1 = (dotNetHelper) => {
return dotNetHelper.invokeMethodAsync('GetHelloMessage');
};
</script>
Note
Per indicazioni generali sulla posizione di JS e sulle nostre raccomandazioni per le app di produzione, vedere Posizione di JavaScript nelle app di ASP.NET Core Blazor.
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 methodpulsante è selezionato, la JS funzionesayHello1viene chiamata con .DotNetObjectReference -
sayHello1:- Chiama
GetHelloMessagee riceve il risultato del messaggio. - Restituisce il risultato del messaggio al metodo chiamante
TriggerDotNetInstanceMethod.
- Chiama
- Il messaggio restituito da
sayHello1inresultviene visualizzato all'utente. - Per evitare una perdita di memoria e consentire la garbage collection, il riferimento all'oggetto .NET creato da DotNetObjectReference viene rilasciato nel metodo
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();
}
}
Nell'esempio precedente il nome dotNetHelper della variabile è arbitrario e può essere modificato in qualsiasi nome preferito.
Usa le linee guida 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.
Passa DotNetObjectReference a 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 oggetto DotNetObjectReference dal metodo OnAfterRenderAsync del ciclo di vita a una classe JS affinché venga usato da più funzioni. Assicurarsi che il codice .NET elimini , DotNetObjectReferencecome illustrato nell'esempio seguente.
Nel componente seguente, i pulsanti Trigger JS function chiamano le funzioni JS impostando la proprietà JSonclick, non l'attributo della direttiva @onclick di 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)
{
try
{
await module.DisposeAsync();
}
catch (JSDisconnectedException)
{
}
}
dotNetHelper?.Dispose();
}
}
Nell'esempio precedente:
-
JSè un'istanza IJSRuntime iniettata. IJSRuntime viene registrato dal Blazor framework. - Il nome
dotNetHelperdella 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 rimane bloccato durante la rimozione del modulo nel caso in cui si perda il circuito SignalR di Blazor. Se il codice precedente viene usato in un'app Blazor WebAssembly, non c'è alcuna connessione SignalR da perdere, quindi è possibile rimuovere il blocco
try-catche lasciare la riga che rilascia il modulo (await module.DisposeAsync();). Per altre informazioni, vedere ASP.NET Core Blazor interoperabilità JavaScript (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 IJSRuntime iniettata. IJSRuntime viene registrato dal Blazor framework. - Il nome
dotNetHelperdella 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 classe
GreetingHelpersviene aggiunta all'oggettowindowper definire la classe a livello globale, il che consente a Blazor di individuare la classe per l'interoperabilità con JS. - Il nome
dotNetHelperdella variabile è arbitrario e può essere modificato in qualsiasi nome preferito.
Note
Per indicazioni generali sulla posizione di JS e sulle nostre raccomandazioni per le app di produzione, vedere Posizione di JavaScript nelle app di ASP.NET Core Blazor.
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:-
UpdateAggiorna in modo sincrono il valore diValuedanewValue. -
UpdateAsyncaggiorna in modo asincrono il valore diValuedanewValuedopo aver creato, con Task.Yield, un'attività awaitable che cede nuovamente in modo asincrono il controllo al contesto corrente quando viene attesa.
-
- Ognuno dei metodi della classe scrive il tipo di
TValuee il valore diValuenella console. La scrittura nella console è solo a scopo dimostrativo. Le applicazioni in produzione in genere evitano di scrivere nella console, preferendo il logging dell'applicazione. Per ulteriori informazioni, vedere registrazione in ASP.NET CoreBlazor e Logging in .NET e ASP.NET Core.
Note
I tipi e i metodi generici aperti non specificano tipi per i segnaposto dei tipi. Al contrario, i tipi generici chiusi specificano tipi per tutti i segnaposto di tipo. Gli esempi in questa sezione illustrano tipi generici chiusi, ma è supportato il richiamo di JS metodi di istanza interop con tipi generici 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
UpdateeUpdateAsyncdella 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.syncInteropriceve un valore booleano che indica se l'interoperabilità JS si verifica nel client. QuandosyncInteropètrue,invokeMethodviene chiamato in modo sicuro. Se il valore disyncInteropèfalse, viene chiamata solo la funzioneinvokeMethodAsyncasincrona perché l'interoperabilità JS viene eseguita in un componente lato server. - A scopo dimostrativo, la chiamata di funzione DotNetObjectReference (
invokeMethodoinvokeMethodAsync), il metodo .NET chiamato (UpdateoUpdateAsync) e l'argomento vengono visualizzati nella console. Gli argomenti usano un numero casuale per consentire di associare la chiamata di funzione JS all’invocazione del metodo .NET (anch’esso scritto nella console sul lato .NET). Il codice di produzione di solito non scrive sulla console, né lato client né lato server. Le app di produzione si basano in genere sulla registrazione delle app. Per ulteriori informazioni, vedere registrazione in ASP.NET CoreBlazor e Logging in .NET 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>
Note
Per indicazioni generali sulla posizione di JS e sulle nostre raccomandazioni per le app di produzione, vedere Posizione di JavaScript nelle app di ASP.NET Core Blazor.
Nel componente GenericsExample seguente:
- La JS funzione
invokeMethodsAsyncviene chiamata quando ilInvoke Interoppulsante è selezionato. - Viene creata una coppia di tipi DotNetObjectReference e passata alla funzione JS per le istanze di
GenericTypecome unstringe unint.
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 IJSRuntime iniettata.
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: Aggiornamento: GenericType<System.String>: stringa 37802
JS: invokeMethodAsync:UpdateAsync('string 53051')
JS: invokeMethod:Update('string 26784')
.NET: Update: GenericType<System.String>: string 26784
JS: invokeMethodAsync:Update(14107)
.NET: Aggiornamento: GenericType<System.Int32>: 14107
JS: invokeMethodAsync:UpdateAsync(48995)
JS: invokeMethod:Update(12872)
.NET: Aggiornamento: 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 sul lato server:
JS: invokeMethodAsync:Update('string 34809')
.NET: Aggiornamento: GenericType<System.String>: string 34809
JS: invokeMethodAsync:UpdateAsync('string 93059')
JS: invokeMethodAsync:Update(41997)
.NET: Aggiornamento: GenericType<System.Int32>: 41997
JS: invokeMethodAsync:UpdateAsync(24652)
.NET: UpdateAsync: GenericType<System.String>: string 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 prevedere in modo affidabile l'ordine di completamento delle chiamate di metodo asincrone.
Esempi di istanze di classe
La funzione seguente sayHello1JS :
- Chiama il
GetHelloMessagemetodo .NET sull'oggetto passato DotNetObjectReference. - Restituisce il messaggio da
GetHelloMessagealsayHello1chiamante.
<script>
window.sayHello1 = (dotNetHelper) => {
return dotNetHelper.invokeMethodAsync('GetHelloMessage');
};
</script>
Note
Per indicazioni generali sul JS posizionamento e sui nostri suggerimenti per le app di produzione, vedi Posizionamento di JavaScript nelle app di 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 metodo CallHelloHelperGetHelloMessage nella classe JsInteropClasses3 seguente invoca la funzione sayHello1JS 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 segnaposto
{JS FUNCTION NAME}è il nome della funzione JS. - Il nome
dotNetHelperdella variabile è arbitrario e può essere modificato in qualsiasi nome preferito. - Il
{.NET METHOD ID}segnaposto è l'identificatore del metodo .NET.
Classe helper per il 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
ListItem1componenti. - Ogni
ListItem1componente è costituito da un messaggio e da un pulsante. - Quando viene selezionato un pulsante del componente
ListItem1, il metodoUpdateMessagediListItem1modifica il testo dell'elemento dell'elenco e nasconde il pulsante.
La classe seguente MessageUpdateInvokeHelper contiene un metodo .NET richiamabile tramite JS, UpdateMessageCaller, per richiamare l'Action specificato quando viene creata un'istanza 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 updateMessageCallerJS richiama il UpdateMessageCaller metodo .NET.
<script>
window.updateMessageCaller = (dotNetHelper) => {
dotNetHelper.invokeMethodAsync('UpdateMessageCaller');
dotNetHelper.dispose();
}
</script>
Note
Per indicazioni generali sulla posizione di JS e sulle nostre raccomandazioni per le app di produzione, vedere Posizione di JavaScript nelle app di ASP.NET Core Blazor.
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 istanza del componente ListItem1 crea un'istanza di MessageUpdateInvokeHelper con un oggetto Action impostato sul suo metodo UpdateMessage.
Quando si seleziona il pulsante InteropCall di un componente ListItem1, viene richiamato updateMessageCaller con un DotNetObjectReference creato per l'istanza MessageUpdateInvokeHelper. Ciò consente al framework di chiamare UpdateMessageCaller sull'istanza MessageUpdateInvokeHelper di ListItem1. 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 componente 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'immagine seguente mostra il componente padre di cui è stato eseguito il rendering dopo aver selezionato il secondo InteropCall pulsante:
- Il secondo
ListItem1componente ha visualizzato ilUpdateMessage Called!messaggio. - Il
InteropCallpulsante per il secondoListItem1componente non è visibile perché la proprietà CSSdisplaydel 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
ListItem2componenti, ovvero un componente condiviso. - Ogni
ListItem2componente è costituito da un messaggio<span>di elemento di elenco e un secondo<span>con unadisplayproprietà CSS impostata suinline-blockper la visualizzazione. - Quando viene selezionato un
ListItem2elemento di elenco dei componenti, taleListItem2UpdateMessagemetodo modifica il testo dell'elemento di elenco nel primo<span>e nasconde il secondo<span>impostando la relativadisplayproprietà sunone.
La funzione seguente assignDotNetHelperJS assegna a DotNetObjectReference un elemento in una proprietà denominata dotNetHelper. La funzione seguente interopCallJS 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>
Note
Per indicazioni generali sulla posizione di JS e sulle nostre raccomandazioni per le app di produzione, vedere Posizione di JavaScript nelle app di ASP.NET Core Blazor.
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 istanza del componente ListItem2 richiama la funzione assignDotNetHelperJS in OnAfterRenderAsync con un riferimento all'elemento (il primo elemento <span> della voce dell'elenco) e l'istanza del componente come DotNetObjectReference.
Quando viene selezionato il messaggio di un componente ListItem2, viene invocato interopCall passando l'elemento <span> come parametro (this), che a sua volta richiama il metodo .NET UpdateMessage. In UpdateMessage, StateHasChanged viene chiamato per aggiornare l'interfaccia utente quando message viene impostato e la proprietà display 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.
DotNetObjectReference viene rilasciato 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 componente 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>
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:
Posizione JavaScript
Carica il codice JavaScript (JS) usando uno degli approcci descritti nell'articolo sulla posizione di JavaScript:
-
Caricare uno script nel markup
<head>(generalmente non consigliato) -
Caricare uno script nel markup
<body> -
Carica uno script da un file JavaScript esterno (
.js) nella stessa directory del componente -
Caricare uno script da un file JavaScript esterno (
.js) - Iniettare uno script prima o dopo che Blazor venga avviato
L'uso di moduli JS per caricare JS è descritto in questo articolo nella sezione Isolamento di JavaScript nei moduli JavaScript.
Warning
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.
Warning
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.
- Gli utenti di una libreria e dei relativi componenti non sono tenuti a importare il file 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 di metodo .NET.
- Chiamate di metodo JavaScript da C# quando il tipo di ritorno ha riferimenti circolari.
Supporto della matrice di byte
Blazor supporta l'interoperabilità JavaScript (JS) con array di byte ottimizzati che evita la codifica e la decodifica degli array di byte in Base64. L'esempio seguente usa l'JSinterop per passare un array di byte a .NET.
Specificare una sendByteArrayJS 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>
Note
Per indicazioni generali sulla posizione di JS e sulle nostre raccomandazioni per le app di produzione, vedere Posizione di JavaScript nelle app di ASP.NET Core Blazor.
CallDotnet8.razor:
@page "/call-dotnet-8"
@using System.Text
@implements IAsyncDisposable
@inject IJSRuntime JS
<PageTitle>Call .NET 8</PageTitle>
<h1>Call .NET Example 8</h1>
<p>
<button id="btn">Send Bytes</button>
</p>
<p>
Quote ©2005 <a href="https://www.uphe.com">Universal Pictures</a>:
<a href="https://www.uphe.com/movies/serenity-2005">Serenity</a><br>
<a href="https://www.imdb.com/name/nm0821612/">Jewel Staite on IMDB</a>
</p>
@code {
private IJSObjectReference? module;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
module = await JS.InvokeAsync<IJSObjectReference>("import",
"./Components/Pages/CallDotnet8.razor.js");
await module.InvokeVoidAsync("addHandlers");
}
}
[JSInvokable]
public static Task<string> ReceiveByteArray(byte[] receivedBytes) =>
Task.FromResult(Encoding.UTF8.GetString(receivedBytes, 0,
receivedBytes.Length));
async ValueTask IAsyncDisposable.DisposeAsync()
{
if (module is not null)
{
try
{
await module.DisposeAsync();
}
catch (JSDisconnectedException)
{
}
}
}
}
CallDotnet8.razor:
@page "/call-dotnet-8"
@using System.Text
@implements IAsyncDisposable
@inject IJSRuntime JS
<PageTitle>Call .NET 8</PageTitle>
<h1>Call .NET Example 8</h1>
<p>
<button id="btn">Send Bytes</button>
</p>
<p>
Quote ©2005 <a href="https://www.uphe.com">Universal Pictures</a>:
<a href="https://www.uphe.com/movies/serenity-2005">Serenity</a><br>
<a href="https://www.imdb.com/name/nm0821612/">Jewel Staite on IMDB</a>
</p>
@code {
private IJSObjectReference? module;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
module = await JS.InvokeAsync<IJSObjectReference>("import",
"./Components/Pages/CallDotnet8.razor.js");
await module.InvokeVoidAsync("addHandlers");
}
}
[JSInvokable]
public static Task<string> ReceiveByteArray(byte[] receivedBytes) =>
Task.FromResult(Encoding.UTF8.GetString(receivedBytes, 0,
receivedBytes.Length));
async ValueTask IAsyncDisposable.DisposeAsync()
{
if (module is not null)
{
try
{
await module.DisposeAsync();
}
catch (JSDisconnectedException)
{
}
}
}
}
CallDotNetExample8.razor:
@page "/call-dotnet-example-8"
@using System.Text
<PageTitle>Call .NET 8</PageTitle>
<h1>Call .NET Example 8</h1>
<p>
<button onclick="sendByteArray()">Send Bytes</button>
</p>
<p>
Quote ©2005 <a href="https://www.uphe.com">Universal Pictures</a>:
<a href="https://www.uphe.com/movies/serenity-2005">Serenity</a><br>
<a href="https://www.imdb.com/name/nm0821612/">Jewel Staite on IMDB</a>
</p>
@code {
[JSInvokable]
public static Task<string> ReceiveByteArray(byte[] receivedBytes)
{
return Task.FromResult(
Encoding.UTF8.GetString(receivedBytes, 0, receivedBytes.Length));
}
}
CallDotNetExample8.razor:
@page "/call-dotnet-example-8"
@using System.Text
<h1>Call .NET Example 8</h1>
<p>
<button onclick="sendByteArray()">Send Bytes</button>
</p>
<p>
Quote ©2005 <a href="https://www.uphe.com">Universal Pictures</a>:
<a href="https://www.uphe.com/movies/serenity-2005">Serenity</a><br>
<a href="https://www.imdb.com/name/nm0821612/">Jewel Staite on IMDB</a>
</p>
@code {
[JSInvokable]
public static Task<string> ReceiveByteArray(byte[] receivedBytes)
{
return Task.FromResult(
Encoding.UTF8.GetString(receivedBytes, 0, receivedBytes.Length));
}
}
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: Un oggetto CancellationToken per annullare l'operazione di 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 IJSRuntime iniettata. IJSRuntime viene registrato dal Blazor framework. - Il
dataReferenceStreamviene scritto su disco (file.txt) nel percorso della cartella temporanea dell'utente corrente (GetTempPath).
Chiamare funzioni JavaScript dai metodi .NET in ASP.NET Core Blazor illustra l'operazione inversa, lo streaming da .NET a JavaScript usando DotNetStreamReference.
Caricamento di file in ASP.NET Core Blazor illustra come caricare un file in Blazor. Per un esempio di form che trasmette dati <textarea> in un componente lato server, vedere Risolvere i problemi dei form di ASP.NET Core Blazor.
Interop JavaScript [JSImport]/[JSExport]
Questa sezione si applica ai componenti lato client.
In alternativa all'uso di JavaScript (JS) nei componenti lato client usando il meccanismo di interoperabilità JS di Blazor basato sull'interfaccia IJSRuntime, per le app destinate a .NET 7 o versioni successive è disponibile un'API di interoperabilità JS[JSImport]/[JSExport].
Per altre informazioni, vedere Interoperabilità JSImport/JSExport JavaScript con ASP.NET Core Blazor.
Eliminazione dei riferimenti agli oggetti di interoperabilità JavaScript
Esempi presenti negli articoli sull'interoperabilità di JavaScript (JS) illustrano i tipici schemi di eliminazione degli oggetti:
Quando si chiama .NET da JS, come descritto in questo articolo, eliminare l'DotNetObjectReference creato da .NET o da JS per evitare perdite di memoria in .NET.
Quando si chiama JS da .NET, come descritto in Chiamare funzioni JavaScript dai metodi .NET in ASP.NET Core Blazor, eliminare qualsiasi IJSObjectReference/IJSInProcessObjectReference/
JSObjectReferencecreato da .NET o da JS per evitare perdite di memoria JS.
JS I riferimenti agli oggetti di interoperabilità vengono implementati come una mappa indicizzata tramite un identificatore dal lato della chiamata di interoperabilità JS 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.
Come minimo, rilasciare sempre gli oggetti creati dal lato .NET per evitare perdite di memoria gestita da .NET.
Attività di pulizia DOM durante l'eliminazione dei componenti
Per altre informazioni, vedere ASP.NET Core Blazor interoperabilità JavaScript (JS interop).
Chiamate di interoperabilità con JavaScript senza un circuito
Per altre informazioni, vedere ASP.NET Core Blazor interoperabilità JavaScript (JS interop).
Risorse aggiuntive
- Chiamare funzioni JavaScript da metodi .NET in ASP.NET Core Blazor
-
InteropComponent.razoresempio (dotnet/AspNetCoreramo del repositorymainGitHub): ilmainramo rappresenta lo sviluppo corrente dell'unità prodotto per la versione successiva di ASP.NET Core. Per selezionare il ramo per una versione diversa, ad esempiorelease/{VERSION}, in cui il segnaposto{VERSION}indica la versione di rilascio, utilizzare l'elenco a discesa Switch branches or tags 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
-
Blazor repository GitHub degli esempi (
dotnet/blazor-samples) (come scaricare) - Gestire gli errori nelle app Blazor ASP.NET Core (sezione Interop JavaScript)
- Mitigazione delle minacce: metodi .NET richiamati dal browser