Interoperabilità JavaScript (interop JS) 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.
Un'app Blazor può richiamare le funzioni JavaScript (JS) dai metodi .NET e i metodi .NET dalle funzioni JS. Questi scenari sono chiamati interoperabilità JavaScript (interop JS).
Altre indicazioni sull'interoperabilità JS sono disponibili negli articoli seguenti:
- Chiamare funzioni JavaScript da metodi .NET in ASP.NET Core Blazor
- Chiamare metodi .NET da funzioni JavaScript in ASP.NET Core Blazor
Nota
L'API di interoperabilità JavaScript [JSImport]
/[JSExport]
è disponibile per i componenti lato client in ASP.NET Core in .NET 7 o versione successiva.
Per altre informazioni, vedere Interoperabilità JSImport/JSExport JavaScript con ASP.NET Core Blazor.
Compressione per componenti server interattivi con dati non attendibili
Con la compressione, abilitata per impostazione predefinita, evitare di creare componenti interattivi interattivi (autenticati/autorizzati) che eseguono il rendering dei dati da origini non attendibili. Le origini non attendibili includono parametri di route, stringhe di query, dati di JS interoperabilità e qualsiasi altra origine di dati che un utente di terze parti può controllare (database, servizi esterni). Per altre informazioni, vedere linee guida ASP.NET Core BlazorSignalR e Linee guida per la mitigazione delle minacce per ASP.NET rendering lato server interattivo CoreBlazor.
Pacchetto di astrazioni e funzionalità di interoperabilità JavaScript
Il @microsoft/dotnet-js-interop
pacchetto () (npmjs.com
Microsoft.JSInterop
pacchetto NuGet) fornisce astrazioni e funzionalità per l'interoperabilità tra il codice .NET e JavaScript (JS). L'origine di riferimento è disponibile nel repository GitHub (cartella).Reference source is available in the dotnet/aspnetcore
GitHub repository (/src/JSInterop
folder). Per altre informazioni, vedere il file del README.md
repository GitHub.
Nota
I collegamenti della documentazione all'origine del riferimento .NET in genere caricano il ramo predefinito del repository, che rappresenta lo sviluppo corrente per la versione successiva di .NET. Per selezionare un tag per una versione specifica, usare l'elenco a discesa Switch branches or tags. Per altre informazioni, vedere How to select a version tag of ASP.NET Core source code (dotnet/AspNetCore.Docs #26205) (Come selezionare un tag di versione del codice sorgente di ASP.NET - dotnet/AspNetCore.Docs #26205).
Risorse aggiuntive per la scrittura di JS script di interoperabilità in TypeScript:
- TypeScript
- Esercitazione: Creare un'app ASP.NET Core con TypeScript in Visual Studio
- Gestire pacchetti npm in Visual Studio
Interazione con il DOM
Modifica il DOM solo con JavaScript (JS) quando l'oggetto non interagisce con Blazor. Blazor gestisce le rappresentazioni del DOM e interagisce direttamente con gli oggetti DOM. Se un elemento sottoposto a rendering da Blazor viene modificato esternamente usando JS direttamente o tramite l'interoperabilità JS, il DOM potrebbe non corrispondere più alla rappresentazione interna di Blazor, causando un comportamento non definito. Il comportamento non definito può semplicemente interferire con la presentazione degli elementi o delle relative funzioni, ma può anche introdurre rischi di sicurezza per l'app o il server.
Queste linee guida non si applicano solo al codice di interoperabilità JS, ma anche a tutte le librerie JS usate dall'app, incluse quelle fornite da un framework di terze parti, ad esempio Bootstrap JS e jQuery.
In alcuni esempi della documentazione, l'interoperabilità JS viene usata per modificare un elemento esclusivamente per scopi dimostrativi nell'ambito di un esempio. In questi casi viene visualizzato un avviso nel testo.
Per altre informazioni, vedere Chiamare funzioni JavaScript da metodi .NET in ASP.NET Core Blazor.
Classe JavaScript con un campo di funzione di tipo
Una classe JavaScript con un campo di funzione di tipo non è supportata dall'interoperabilità BlazorJS . Usare le funzioni Javascript nelle classi.
Non supportato: GreetingHelpers.sayHello
nella classe seguente come campo di funzione di tipo non viene individuato dall'interoperabilità Blazordi 's JS e non può essere eseguito dal codice C#:
export class GreetingHelpers {
sayHello = function() {
...
}
}
nella classe seguente come funzione è supportata:
export class GreetingHelpers {
sayHello() {
...
}
}
Sono supportate anche le funzioni freccia:
export class GreetingHelpers {
sayHello = () => {
...
}
}
Evitare gestori eventi inline
Una funzione JavaScript può essere richiamata direttamente da un gestore eventi inline. Nell'esempio seguente è alertUser
una funzione JavaScript chiamata quando il pulsante viene selezionato dall'utente:
<button onclick="alertUser">Click Me!</button>
Tuttavia, l'uso di gestori eventi inline è una scelta di progettazione scarsa per chiamare le funzioni JavaScript:
- La combinazione di markup HTML e codice JavaScript spesso comporta codice non gestibile.
- L'esecuzione del gestore eventi inline può essere bloccata da un CSP (Content Security Policy) (documentazione MDN).
È consigliabile evitare gestori eventi inline a favore di approcci che assegnano gestori in JavaScript con addEventListener
, come illustrato nell'esempio seguente:
AlertUser.razor.js
:
export function alertUser() {
alert('The button was selected!');
}
export function addHandlers() {
const btn = document.getElementById("btn");
btn.addEventListener("click", alertUser);
}
AlertUser.razor
:
@page "/alert-user"
@implements IAsyncDisposable
@inject IJSRuntime JS
<h1>Alert User</h1>
<p>
<button id="btn">Click Me!</button>
</p>
@code {
private IJSObjectReference? module;
protected async override Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
module = await JS.InvokeAsync<IJSObjectReference>("import",
"./Components/Pages/AlertUser.razor.js");
await module.InvokeVoidAsync("addHandlers");
}
}
async ValueTask IAsyncDisposable.DisposeAsync()
{
if (module is not null)
{
try
{
await module.DisposeAsync();
}
catch (JSDisconnectedException)
{
}
}
}
}
Nell'esempio precedente, 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 ilcatch
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).
Per ulteriori informazioni, vedi le seguenti risorse:
Chiamate JavaScript asincrone
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 i modelli di rendering lato server e lato client. Quando si adotta il rendering lato server, JS le chiamate di interoperabilità devono essere asincrone perché vengono inviate tramite una connessione di rete. Per le app che adottano esclusivamente il rendering lato client, sono supportate chiamate di interoperabilità sincrone JS .
Per altre informazioni, vedere gli articoli seguenti:
Per altre informazioni, vedere Chiamare funzioni JavaScript da metodi .NET in ASP.NET Core Blazor.
Serializzazione degli oggetti
Blazor usa System.Text.Json per la serializzazione con i requisiti e i comportamenti predefiniti seguenti:
- I tipi devono avere un costruttore predefinito, le funzioni di accesso
get
/set
devono essere pubbliche e i campi non vengono mai serializzati. - La serializzazione predefinita globale non è personalizzabile per evitare l'interruzione delle librerie di componenti esistenti, l'impatto sulle prestazioni e sulla sicurezza e la riduzione dell'affidabilità.
- La serializzazione dei nomi dei membri .NET comporta nomi di chiave JSON minuscoli.
- JSON viene deserializzato come JsonElement istanze C#, che consentono maiuscole e minuscole miste. Il cast interno per l'assegnazione alle proprietà del modello C# funziona come previsto, nonostante le differenze tra i nomi delle chiavi JSON e i nomi delle proprietà C#.
- I tipi di framework complessi, ad esempio KeyValuePair, potrebbero essere eliminati dal trimmer IL durante la pubblicazione e non presenti per JS l'interoperabilità. È consigliabile creare tipi personalizzati per i tipi rimossi dal trimmer IL.
- Blazorsi basa sempre sulla reflection per la serializzazione JSON, incluso quando si usa la generazione di origine C#. L'impostazione su
JsonSerializerIsReflectionEnabledByDefault
false
nel file di progetto dell'app genera un errore quando viene tentata la serializzazione.
L'API JsonConverter è disponibile per la serializzazione personalizzata. È possibile annotare le proprietà con un attributo [JsonConverter]
per eseguire l'override della serializzazione predefinita per un tipo di dati esistente.
Per altre informazioni, vedere le risorse seguenti nella documentazione di .NET:
- Serializzazione e deserializzazione JSON (marshalling e annullamento del marshalling) in .NET
- Come personalizzare nomi e valori di proprietà con
System.Text.Json
- Come scrivere convertitori personalizzati per la serializzazione (marshalling) JSON in .NET
Blazor supporta l'interoperabilità JS ottimizzata per le matrici di byte, che evita la codifica/decodifica delle matrici di byte in Base 64. L'app può applicare la serializzazione personalizzata e passare i byte risultanti. Per altre informazioni, vedere Chiamare funzioni JavaScript da metodi .NET in ASP.NET Core Blazor.
Blazor supporta l'interoperabilità JS senza marshalling quando un volume elevato di oggetti .NET viene rapidamente serializzato oppure quando è necessario serializzare oggetti .NET di grandi dimensioni o molti oggetti .NET. Per altre informazioni, vedere Chiamare funzioni JavaScript da metodi .NET in ASP.NET Core Blazor.
Attività di pulizia DOM durante l'eliminazione dei componenti
Non eseguire JS codice di interoperabilità per le attività di pulizia DOM durante l'eliminazione del componente. Usare invece il MutationObserver
modello in JavaScript (JS) nel client per i motivi seguenti:
- Il componente potrebbe essere stato rimosso dal DOM al momento dell'esecuzione del codice di pulizia in
Dispose{Async}
. - Durante il rendering lato server, il Blazor renderer potrebbe essere stato eliminato dal framework al momento dell'esecuzione del codice di pulizia in
Dispose{Async}
.
Il MutationObserver
modello consente di eseguire una funzione quando un elemento viene rimosso dal DOM.
Nell'esempio seguente il DOMCleanup
componente :
- Contiene un
<div>
oggetto con unid
oggetto dicleanupDiv
. L'elemento<div>
viene rimosso dal DOM insieme all'oggetto rest del markup DOM del componente quando il componente viene rimosso dal DOM. - Carica la
DOMCleanup
JS classe dalDOMCleanup.razor.js
file e chiama la relativacreateObserver
funzione per configurare ilMutationObserver
callback. Queste attività vengono eseguite nel metodo delOnAfterRenderAsync
ciclo di vita.
DOMCleanup.razor
:
@page "/dom-cleanup"
@implements IAsyncDisposable
@inject IJSRuntime JS
<h1>DOM Cleanup Example</h1>
<div id="cleanupDiv"></div>
@code {
private IJSObjectReference? module;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
module = await JS.InvokeAsync<IJSObjectReference>(
"import", "./Components/Pages/DOMCleanup.razor.js");
await module.InvokeVoidAsync("DOMCleanup.createObserver");
}
}
async ValueTask IAsyncDisposable.DisposeAsync()
{
if (module is not null)
{
try
{
await module.DisposeAsync();
}
catch (JSDisconnectedException)
{
}
}
}
}
Nell'esempio precedente, 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 ilcatch
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).
Nell'esempio seguente il MutationObserver
callback viene eseguito ogni volta che si verifica una modifica DOM. Eseguire il codice di pulizia quando l'istruzione if
conferma che l'elemento di destinazione (cleanupDiv
) è stato rimosso (if (targetRemoved) { ... }
). È importante disconnettersi ed eliminare per MutationObserver
evitare una perdita di memoria dopo l'esecuzione del codice di pulizia.
DOMCleanup.razor.js
posizionato side-by-side con il componente precedente DOMCleanup
:
export class DOMCleanup {
static observer;
static createObserver() {
const target = document.querySelector('#cleanupDiv');
this.observer = new MutationObserver(function (mutations) {
const targetRemoved = mutations.some(function (mutation) {
const nodes = Array.from(mutation.removedNodes);
return nodes.indexOf(target) !== -1;
});
if (targetRemoved) {
// Cleanup resources here
// ...
// Disconnect and delete MutationObserver
this.observer && this.observer.disconnect();
delete this.observer;
}
});
this.observer.observe(target.parentNode, { childList: true });
}
}
window.DOMCleanup = DOMCleanup;
Chiamate di interoperabilità JavaScript senza circuito
Questa sezione si applica solo alle app lato server.
Le chiamate di interoperabilità JavaScript (JS) non possono essere eseguite dopo Blazorla disconnessione del circuito.SignalR Senza un circuito durante l'eliminazione di un componente o in qualsiasi altro momento in cui un circuito non esiste, le chiamate al metodo seguenti hanno esito negativo e registrano un messaggio che indica che il circuito viene disconnesso come JSDisconnectedException:
- JS chiamate al metodo di interoperabilità
Dispose
/DisposeAsync
chiama su qualsiasi IJSObjectReferenceoggetto .
Per evitare la registrazione JSDisconnectedException o registrare informazioni personalizzate, intercettare l'eccezione in un'istruzione try-catch
.
Per l'esempio di eliminazione dei componenti seguente:
- Il componente lato server implementa IAsyncDisposable.
module
è un IJSObjectReference oggetto per un JS modulo.- JSDisconnectedException viene intercettata e non registrata.
- Facoltativamente, è possibile registrare informazioni personalizzate nell'istruzione
catch
a qualsiasi livello di log preferito. L'esempio seguente non registra informazioni personalizzate perché presuppone che lo sviluppatore non si preoccupi quando o dove i circuiti vengono disconnessi durante l'eliminazione del componente.
async ValueTask IAsyncDisposable.DisposeAsync()
{
try
{
if (module is not null)
{
await module.DisposeAsync();
}
}
catch (JSDisconnectedException)
{
}
}
Se è necessario pulire i propri JS oggetti o eseguire altro JS codice sul client dopo la perdita di un circuito in un'app lato Blazor server, usare il MutationObserver
modello in JS nel client. Il MutationObserver
modello consente di eseguire una funzione quando un elemento viene rimosso dal DOM.
Per altre informazioni, vedere gli articoli seguenti:
- Gestire gli errori nelle app di base ASP.NETBlazor: la sezione Interoperabilità JavaScript illustra la gestione degli errori negli JS scenari di interoperabilità.
- ASP.NET ciclo di vita dei componenti principaliRazor: la sezione Eliminazione dei componenti con
IDisposable
eIAsyncDisposable
descrive come implementare i modelli di eliminazione nei Razor componenti.
File JavaScript memorizzati nella cache
I file JavaScript (JS) e gli altri asset statici in genere non vengono memorizzati nella cache dei client durante lo sviluppo nell'ambiente Development
. Durante lo sviluppo, le richieste di asset statici includono l'intestazione Cache-Control
con il valore no-cache
o max-age
con un valore pari a zero (0
).
Durante la produzione nell'ambiente Production
, JS i file vengono in genere memorizzati nella cache dai client.
Per disabilitare la memorizzazione nella cache lato client nei browser, gli sviluppatori adottano in genere uno degli approcci seguenti:
- Disabilitare la memorizzazione nella cache quando la console degli strumenti di sviluppo del browser è aperta. Le indicazioni sono disponibili nella documentazione degli strumenti di sviluppo di ogni operatore di gestione del browser:
- Chrome DevTools (Strumenti di sviluppo di Chrome)
- Panoramica degli strumenti di sviluppo di Microsoft Edge
- Eseguire un aggiornamento manuale del browser per ogni pagina Web dell'app Blazor per ricaricare i file JS dal server. Il middleware di memorizzazione nella cache HTTP di ASP.NET Core rispetta sempre un'intestazione
Cache-Control
no-cache valida inviata da un client.
Per altre informazioni, vedi:
Limiti di dimensioni per le chiamate di interoperabilità JavaScript
Questa sezione si applica solo ai componenti interattivi nelle app lato server. Per i componenti lato client, il framework non impone un limite alle dimensioni degli input e degli output di interoperabilità JavaScript (JS).
Per i componenti interattivi nelle app lato server, JS le chiamate di interoperabilità che passano dati dal client al server sono limitate in base alle dimensioni massime SignalR consentite per i metodi hub, che vengono applicate per impostazione HubOptions.MaximumReceiveMessageSize predefinita: 32 KB. JS per i messaggi .NET SignalR di dimensioni maggiori rispetto MaximumReceiveMessageSize a generare un errore. Il framework non impone un limite alle dimensioni di un SignalR messaggio dall'hub a un client. Per altre informazioni sul limite di dimensioni, i messaggi di errore e le indicazioni sulla gestione dei limiti delle dimensioni dei messaggi, vedere ASP.NET Linee guida di baseBlazorSignalR.
Determinare dove è in esecuzione l'app
Se è rilevante per l'app sapere dove è in esecuzione il codice per JS le chiamate di interoperabilità, usare OperatingSystem.IsBrowser per determinare se il componente è in esecuzione nel contesto del browser in WebAssembly.