Interoperabilità JavaScript [JSImport]/[JSExport] con ASP.NET Core Blazor

Nota

Questa non è la versione più recente di questo articolo. Per la versione corrente, vedere la versione .NET 8 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 8 di questo articolo.

Questo articolo illustra come interagire con JavaScript (JS) nei componenti lato client usando l'API di interoperabilità JavaScript (JS) [JSImport]/[JSExport] rilasciata per le app che adottano .NET 7 o versioni successive.

Blazor fornisce il proprio JS meccanismo di interoperabilità basato sull'interfaccia IJSRuntime . BlazorL'interoperabilità di JS è supportata in modo uniforme tra Blazor le modalità di rendering e per Blazor Hybrid le app. IJSRuntimeconsente anche agli autori di librerie di creare JS librerie di interoperabilità per la condivisione nell'ecosistema e rimane l'approccio consigliato per JS l'interoperabilità Blazor in Blazor. Fai riferimento ai seguenti articoli:

Questo articolo descrive un approccio di interoperabilità alternativo JS specifico per i componenti lato client eseguiti in WebAssembly. Questi approcci sono appropriati quando si prevede solo l'esecuzione su WebAssembly sul lato client. Gli autori di librerie possono usare questi approcci per ottimizzare JS l'interoperabilità controllando durante l'esecuzione del codice se l'app è in esecuzione in WebAssembly in un browser (OperatingSystem.IsBrowser). Gli approcci descritti in questo articolo devono essere usati per sostituire l'API obsoleta di interoperabilità nonmarshalled JS durante la migrazione a .NET 7 o versione successiva.

Nota

Questo articolo è incentrato sull'interoperabilità JS nei componenti lato client. Per indicazioni sulla chiamata di .NET nelle app JavaScript, vedere Eseguire .NET da JavaScript.

API di interoperabilità JavaScript obsoleta

L'interoperabilità non interrotta JS con l'API IJSUnmarshalledRuntime è obsoleta in ASP.NET Core in .NET 7 o versione successiva. Seguire le indicazioni riportate in questo articolo per sostituire l'API obsoleta.

Prerequisiti

Scaricare e installare .NET 7 o versione successiva se non è già installato nel sistema o se il sistema non ha installato la versione più recente.

Spazio dei nomi

L'API JS di interoperabilità descritta in questo articolo è controllata dagli attributi nello spazio dei System.Runtime.InteropServices.JavaScript nomi .

Abilitare blocchi non sicuri

Abilitare la AllowUnsafeBlocks proprietà nel file di progetto dell'app, che consente al generatore di codice nel compilatore Roslyn di usare i puntatori per JS l'interoperabilità:

<PropertyGroup>
  <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>

Avviso

L'API di interoperabilità richiede l'abilitazione JS di AllowUnsafeBlocks. Prestare attenzione quando si implementa codice non sicuro nelle app .NET, che possono introdurre rischi per la sicurezza e la stabilità. Per altre informazioni, vedere Codice unsafe, tipi di puntatore e puntatori a funzione.

Chiamare JavaScript da .NET

Questa sezione illustra come chiamare JS le funzioni da .NET.

Nel componente CallJavaScript1 seguente:

  • Il CallJavaScript1 modulo viene importato in modo asincrono dal file collocato JS con JSHost.ImportAsync.
  • La funzione importata getMessageJS viene chiamata da GetWelcomeMessage.
  • La stringa del messaggio di benvenuto restituita viene visualizzata nell'interfaccia utente tramite il message campo .

CallJavaScript1.razor:

@page "/call-javascript-1"
@rendermode InteractiveWebAssembly
@using System.Runtime.InteropServices.JavaScript

<h1>
    JS <code>[JSImport]</code>/<code>[JSExport]</code> Interop 
    (Call JS Example 1)
</h1>

@(message is not null ? message : string.Empty)

@code {
    private string? message;

    protected override async Task OnInitializedAsync()
    {
        await JSHost.ImportAsync("CallJavaScript1", 
            "../Components/Pages/CallJavaScript1.razor.js");

        message = GetWelcomeMessage();
    }
}
@page "/call-javascript-1"
@using System.Runtime.InteropServices.JavaScript

<h1>
    JS <code>[JSImport]</code>/<code>[JSExport]</code> Interop 
    (Call JS Example 1)
</h1>

@(message is not null ? message : string.Empty)

@code {
    private string? message;

    protected override async Task OnInitializedAsync()
    {
        await JSHost.ImportAsync("CallJavaScript1", 
            "../Pages/CallJavaScript1.razor.js");

        message = GetWelcomeMessage();
    }
}

Nota

Includere un controllo condizionale nel codice con OperatingSystem.IsBrowser per assicurarsi che l'interoperabilità JS venga chiamata solo da un componente sottoposto a rendering sul client. Questo aspetto è importante per le librerie/pacchetti NuGet destinati ai componenti lato server, che non possono eseguire il codice fornito da questa JS API di interoperabilità.

Per importare una JS funzione per chiamarla da C#, usare l'attributo[JSImport] in una firma del metodo C# corrispondente alla JS firma della funzione. Il primo parametro dell'attributo [JSImport] è il nome della JS funzione da importare e il secondo parametro è il nome del JS modulo.

Nell'esempio seguente è getMessage una JS funzione che restituisce un string oggetto per un modulo denominato CallJavaScript1. La firma del metodo C# corrisponde a: nessun parametro viene passato alla JS funzione e la JS funzione restituisce un oggetto string. La JS funzione viene chiamata da GetWelcomeMessage nel codice C#.

CallJavaScript1.razor.cs:

using System.Runtime.InteropServices.JavaScript;
using System.Runtime.Versioning;

namespace BlazorSample.Components.Pages;

[SupportedOSPlatform("browser")]
public partial class CallJavaScript1
{
    [JSImport("getMessage", "CallJavaScript1")]
    internal static partial string GetWelcomeMessage();
}

Lo spazio dei nomi dell'app per la classe parziale precedente CallJavaScript1 è BlazorSample. Lo spazio dei nomi del componente è BlazorSample.Components.Pages. Se si usa il componente precedente in un'app di test locale, aggiornare lo spazio dei nomi in modo che corrisponda all'app. Ad esempio, lo spazio dei nomi è ContosoApp.Components.Pages se lo spazio dei nomi dell'app è ContosoApp. Per altre informazioni, vedere ASP.NET Componenti di baseRazor.

using System.Runtime.InteropServices.JavaScript;
using System.Runtime.Versioning;

namespace BlazorSample.Pages;

[SupportedOSPlatform("browser")]
public partial class CallJavaScript1
{
    [JSImport("getMessage", "CallJavaScript1")]
    internal static partial string GetWelcomeMessage();
}

Lo spazio dei nomi dell'app per la classe parziale precedente CallJavaScript1 è BlazorSample. Lo spazio dei nomi del componente è BlazorSample.Pages. Se si usa il componente precedente in un'app di test locale, aggiornare lo spazio dei nomi in modo che corrisponda all'app. Ad esempio, lo spazio dei nomi è ContosoApp.Pages se lo spazio dei nomi dell'app è ContosoApp. Per altre informazioni, vedere ASP.NET Componenti di baseRazor.

Nella firma del metodo importato è possibile usare i tipi .NET per i parametri e i valori restituiti, che vengono eseguiti automaticamente dal runtime. Usare JSMarshalAsAttribute<T> per controllare la modalità di marshalling dei parametri del metodo importato. Ad esempio, è possibile scegliere di effettuare il marshalling di System.Runtime.InteropServices.JavaScript.JSType.Number come long o System.Runtime.InteropServices.JavaScript.JSType.BigInt. È possibile passare Action/Func<TResult> i callback come parametri, che vengono marshallati come funzioni chiamabili JS . È possibile passare JS riferimenti a oggetti gestiti e vengono sottoposto a marshalling come oggetti proxy, mantenendo attivo l'oggetto oltre il limite fino a quando il proxy non viene sottoposto a Garbage Collection. È anche possibile importare ed esportare metodi asincroni con un Task risultato, di cui viene eseguito il marshalling come JS promesse. La maggior parte dei tipi con marshalling funziona in entrambe le direzioni, come parametri e come valori restituiti, sia nei metodi importati che in quello esportato, illustrati nella sezione Chiamare .NET da JavaScript più avanti in questo articolo.

La tabella seguente indica i mapping dei tipi supportati.

.NET JavaScript Nullable Task➔aPromise JSMarshalAs Opzionale Array of
Boolean Boolean Supportata Supportata Supportata Non supportato
Byte Number Supportata Supportata Supportata Supportata
Char String Supportata Supportata Supportata Non supportato
Int16 Number Supportata Supportata Supportata Non supportato
Int32 Number Supportata Supportata Supportata Supportata
Int64 Number Supportata Supportata Non supportato Non supportato
Int64 BigInt Supportata Supportata Non supportato Non supportato
Single Number Supportata Supportata Supportata Non supportato
Double Number Supportata Supportata Supportata Supportata
IntPtr Number Supportata Supportata Supportata Non supportato
DateTime Date Supportata Supportata Non supportato Non supportato
DateTimeOffset Date Supportata Supportata Non supportato Non supportato
Exception Error Non supportato Supportata Supportata Non supportato
JSObject Object Non supportato Supportata Supportata Supportata
String String Non supportato Supportata Supportata Supportata
Object Any Non supportato Supportata Non supportato Supportata
Span<Byte> MemoryView Non supportato Non supportato Non supportato Non supportato
Span<Int32> MemoryView Non supportato Non supportato Non supportato Non supportato
Span<Double> MemoryView Non supportato Non supportato Non supportato Non supportato
ArraySegment<Byte> MemoryView Non supportato Non supportato Non supportato Non supportato
ArraySegment<Int32> MemoryView Non supportato Non supportato Non supportato Non supportato
ArraySegment<Double> MemoryView Non supportato Non supportato Non supportato Non supportato
Task Promise Non supportato Non supportato Supportata Non supportato
Action Function Non supportato Non supportato Non supportato Non supportato
Action<T1> Function Non supportato Non supportato Non supportato Non supportato
Action<T1, T2> Function Non supportato Non supportato Non supportato Non supportato
Action<T1, T2, T3> Function Non supportato Non supportato Non supportato Non supportato
Func<TResult> Function Non supportato Non supportato Non supportato Non supportato
Func<T1, TResult> Function Non supportato Non supportato Non supportato Non supportato
Func<T1, T2, TResult> Function Non supportato Non supportato Non supportato Non supportato
Func<T1, T2, T3, TResult> Function Non supportato Non supportato Non supportato Non supportato

Le condizioni seguenti si applicano al mapping dei tipi e ai valori con marshalling:

  • La Array of colonna indica se il tipo .NET può essere sottoposto a marshalling come JSArray. Esempio: C# int[] (Int32) mappato a JSArray s Number.
  • Quando si passa un JS valore a C# con un valore di tipo errato, il framework genera un'eccezione nella maggior parte dei casi. Il framework non esegue il controllo dei tipi in fase di compilazione in JS.
  • JSObject, ExceptionTask e ArraySegment creare GCHandle e un proxy. È possibile attivare l'eliminazione nel codice dello sviluppatore o consentire a .NET Garbage Collection (GC) di eliminare gli oggetti in un secondo momento. Questi tipi comportano un sovraccarico significativo delle prestazioni.
  • Array: il marshalling di una matrice crea una copia della matrice in JS o .NET.
  • MemoryView
    • MemoryView è una JS classe per il runtime .NET WebAssembly di effettuare il marshalling Span e ArraySegment.
    • A differenza del marshalling di una matrice, il marshalling di un Span oggetto o ArraySegment non crea una copia della memoria sottostante.
    • MemoryView può essere creata correttamente dall'istanza del runtime .NET WebAssembly. Non è quindi possibile importare una JS funzione come metodo .NET con un parametro di Span o ArraySegment.
    • MemoryView creato per un Span oggetto è valido solo per la durata della chiamata di interoperabilità. Poiché Span viene allocato nello stack di chiamate, che non viene salvato in modo permanente dopo la chiamata di interoperabilità, non è possibile esportare un metodo .NET che restituisce un oggetto Span.
    • MemoryView creato per un oggetto ArraySegment sopravvive dopo la chiamata di interoperabilità ed è utile per la condivisione di un buffer. La chiamata dispose() a un MemoryView oggetto creato per un ArraySegment oggetto elimina il proxy e rimuove la matrice .NET sottostante. È consigliabile chiamare dispose() in un try-finally blocco per MemoryView.

La tabella seguente indica i mapping dei tipi supportati.

.NET JavaScript Nullable Task➔aPromise JSMarshalAs Opzionale Array of
Boolean Boolean Supportata Supportata Supportata Non supportato
Byte Number Supportata Supportata Supportata Supportata
Char String Supportata Supportata Supportata Non supportato
Int16 Number Supportata Supportata Supportata Non supportato
Int32 Number Supportata Supportata Supportata Supportata
Int64 Number Supportata Supportata Non supportato Non supportato
Int64 BigInt Supportata Supportata Non supportato Non supportato
Single Number Supportata Supportata Supportata Non supportato
Double Number Supportata Supportata Supportata Supportata
IntPtr Number Supportata Supportata Supportata Non supportato
DateTime Date Supportata Supportata Non supportato Non supportato
DateTimeOffset Date Supportata Supportata Non supportato Non supportato
Exception Error Non supportato Supportata Supportata Non supportato
JSObject Object Non supportato Supportata Supportata Supportata
String String Non supportato Supportata Supportata Supportata
Object Any Non supportato Supportata Non supportato Supportata
Span<Byte> MemoryView Non supportato Non supportato Non supportato Non supportato
Span<Int32> MemoryView Non supportato Non supportato Non supportato Non supportato
Span<Double> MemoryView Non supportato Non supportato Non supportato Non supportato
ArraySegment<Byte> MemoryView Non supportato Non supportato Non supportato Non supportato
ArraySegment<Int32> MemoryView Non supportato Non supportato Non supportato Non supportato
ArraySegment<Double> MemoryView Non supportato Non supportato Non supportato Non supportato
Task Promise Non supportato Non supportato Supportata Non supportato
Action Function Non supportato Non supportato Non supportato Non supportato
Action<T1> Function Non supportato Non supportato Non supportato Non supportato
Action<T1, T2> Function Non supportato Non supportato Non supportato Non supportato
Action<T1, T2, T3> Function Non supportato Non supportato Non supportato Non supportato
Func<TResult> Function Non supportato Non supportato Non supportato Non supportato
Func<T1, TResult> Function Non supportato Non supportato Non supportato Non supportato
Func<T1, T2, TResult> Function Non supportato Non supportato Non supportato Non supportato
Func<T1, T2, T3, TResult> Function Non supportato Non supportato Non supportato Non supportato

Le condizioni seguenti si applicano al mapping dei tipi e ai valori con marshalling:

  • La Array of colonna indica se il tipo .NET può essere sottoposto a marshalling come JSArray. Esempio: C# int[] (Int32) mappato a JSArray s Number.
  • Quando si passa un JS valore a C# con un valore di tipo errato, il framework genera un'eccezione nella maggior parte dei casi. Il framework non esegue il controllo dei tipi in fase di compilazione in JS.
  • JSObject, ExceptionTask e ArraySegment creare GCHandle e un proxy. È possibile attivare l'eliminazione nel codice dello sviluppatore o consentire a .NET Garbage Collection (GC) di eliminare gli oggetti in un secondo momento. Questi tipi comportano un sovraccarico significativo delle prestazioni.
  • Array: il marshalling di una matrice crea una copia della matrice in JS o .NET.
  • MemoryView
    • MemoryView è una JS classe per il runtime .NET WebAssembly di effettuare il marshalling Span e ArraySegment.
    • A differenza del marshalling di una matrice, il marshalling di un Span oggetto o ArraySegment non crea una copia della memoria sottostante.
    • MemoryView può essere creata correttamente dall'istanza del runtime .NET WebAssembly. Non è quindi possibile importare una JS funzione come metodo .NET con un parametro di Span o ArraySegment.
    • MemoryView creato per un Span oggetto è valido solo per la durata della chiamata di interoperabilità. Poiché Span viene allocato nello stack di chiamate, che non viene salvato in modo permanente dopo la chiamata di interoperabilità, non è possibile esportare un metodo .NET che restituisce un oggetto Span.
    • MemoryView creato per un oggetto ArraySegment sopravvive dopo la chiamata di interoperabilità ed è utile per la condivisione di un buffer. La chiamata dispose() a un MemoryView oggetto creato per un ArraySegment oggetto elimina il proxy e rimuove la matrice .NET sottostante. È consigliabile chiamare dispose() in un try-finally blocco per MemoryView.

Il nome del modulo nell'attributo [JSImport] e la chiamata per caricare il modulo nel componente con JSHost.ImportAsync deve corrispondere e essere univoco nell'app. Quando si crea una libreria per la distribuzione in un pacchetto NuGet, è consigliabile usare lo spazio dei nomi del pacchetto NuGet come prefisso nei nomi dei moduli. Nell'esempio seguente il nome del modulo riflette il Contoso.InteropServices.JavaScript pacchetto e una cartella di classi di interoperabilità dei messaggi utente (UserMessages):

[JSImport("getMessage", 
    "Contoso.InteropServices.JavaScript.UserMessages.CallJavaScript1")]

Le funzioni accessibili nello spazio dei nomi globale possono essere importate usando il globalThis prefisso nel nome della funzione e usando l'attributo [JSImport] senza specificare un nome di modulo. Nell'esempio seguente, console.log è preceduto da globalThis. La funzione importata viene chiamata dal metodo C# Log , che accetta un messaggio stringa C# (message) e esegue il marshalling della stringa C# in un JSString per console.log:

[JSImport("globalThis.console.log")]
internal static partial void Log([JSMarshalAs<JSType.String>] string message);

Esportare script da un modulo JavaScript ES6 standard collocato con un componente o inserito con altri asset statici JavaScript in un JS file ( ad esempio , wwwroot/js/{FILE NAME}.jsdove JS gli asset statici vengono mantenuti in una cartella denominata js nella cartella dell'app wwwroot e il {FILE NAME} segnaposto è il nome file).

Nell'esempio seguente una JS funzione denominata getMessage viene esportata da un file collocato JS che restituisce un messaggio di benvenuto, "Hello from Blazor!" in portoghese:

CallJavaScript1.razor.js:

export function getMessage() {
  return 'Olá do Blazor!';
}

Chiamare .NET da JavaScript

Questa sezione illustra come chiamare i metodi .NET da JS.

Il componente seguente CallDotNet1 chiama JS che interagisce direttamente con il DOM per eseguire il rendering della stringa del messaggio di benvenuto:

  • Il CallDotNetJS modulo viene importato in modo asincrono dal file collocato JS per questo componente.
  • La funzione importata setMessageJS viene chiamata da SetWelcomeMessage.
  • Il messaggio di benvenuto restituito viene visualizzato dall'interfaccia setMessage utente tramite il message campo .

Importante

Nell'esempio di questa sezione viene JS usata l'interoperabilità per modificare un elemento DOM esclusivamente a scopo dimostrativo dopo il rendering del componente in OnAfterRender. In genere, è consigliabile modificare il DOM solo con JS quando l'oggetto non interagisce con Blazor. L'approccio illustrato in questa sezione è simile ai casi in cui una libreria di terze parti JS viene usata in un Razor componente, in cui il componente interagisce con la JS libreria tramite JS interoperabilità, la libreria di terze parti JS interagisce con parte del DOM e Blazor non è coinvolta direttamente con gli aggiornamenti DOM a tale parte del DOM. Per altre informazioni, vedere ASP.NET Core JavaScript interoperabilità (interoperabilità).For more information, see ASP.NET Core Blazor JavaScript interoperability (JS interop).

CallDotNet1.razor:

@page "/call-dotnet-1"
@rendermode InteractiveWebAssembly
@using System.Runtime.InteropServices.JavaScript

<h1>
    JS <code>[JSImport]</code>/<code>[JSExport]</code> Interop 
    (Call .NET Example 1)
</h1>

<p>
    <span id="result">.NET method not executed yet</span>
</p>

@code {
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            await JSHost.ImportAsync("CallDotNet1", 
                "../Components/Pages/CallDotNet1.razor.js");

            SetWelcomeMessage();
        }
    }
}
@page "/call-dotnet-1"
@using System.Runtime.InteropServices.JavaScript

<h1>
    JS <code>[JSImport]</code>/<code>[JSExport]</code> Interop 
    (Call .NET Example 1)
</h1>

<p>
    <span id="result">.NET method not executed yet</span>
</p>

@code {
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            await JSHost.ImportAsync("CallDotNet1", 
                "../Pages/CallDotNet1.razor.js");

            SetWelcomeMessage();
        }
    }
}

Per esportare un metodo .NET in modo che possa essere chiamato da JS, usare l'attributo[JSExport].

Nell'esempio seguente :

  • SetWelcomeMessage chiama una JS funzione denominata setMessage. La JS funzione chiama in .NET per ricevere il messaggio di benvenuto da GetMessageFromDotnet e visualizza il messaggio nell'interfaccia utente.
  • GetMessageFromDotnet è un metodo .NET con l'attributo [JSExport] che restituisce un messaggio di benvenuto, "Hello from Blazor!" in portoghese.

CallDotNet1.razor.cs:

using System.Runtime.InteropServices.JavaScript;
using System.Runtime.Versioning;

namespace BlazorSample.Components.Pages;

[SupportedOSPlatform("browser")]
public partial class CallDotNet1
{
    [JSImport("setMessage", "CallDotNet1")]
    internal static partial void SetWelcomeMessage();

    [JSExport]
    internal static string GetMessageFromDotnet()
    {
        return "Olá do Blazor!";
    }
}

Lo spazio dei nomi dell'app per la classe parziale precedente CallDotNet1 è BlazorSample. Lo spazio dei nomi del componente è BlazorSample.Components.Pages. Se si usa il componente precedente in un'app di test locale, aggiornare lo spazio dei nomi dell'app in modo che corrisponda all'app. Ad esempio, lo spazio dei nomi del componente è ContosoApp.Components.Pages se lo spazio dei nomi dell'app è ContosoApp. Per altre informazioni, vedere ASP.NET Componenti di baseRazor.

Nell'esempio seguente viene importata una JS funzione denominata setMessage da un file collocato JS .

Il metodo setMessage:

  • Chiama globalThis.getDotnetRuntime(0) per esporre l'istanza di runtime .NET di WebAssembly per chiamare i metodi .NET esportati.
  • Ottiene le esportazioni dell'assembly dell'app JS . Il nome dell'assembly dell'app nell'esempio seguente è BlazorSample.
  • Chiama il BlazorSample.Components.Pages.CallDotNet1.GetMessageFromDotnet metodo dalle esportazioni (exports). Il valore restituito, ovvero il messaggio di benvenuto, viene assegnato al CallDotNet1 testo del <span> componente. Lo spazio dei nomi dell'app è BlazorSamplee lo CallDotNet1 spazio dei nomi del componente è BlazorSample.Components.Pages.

CallDotNet1.razor.js:

export async function setMessage() {
  const { getAssemblyExports } = await globalThis.getDotnetRuntime(0);
  var exports = await getAssemblyExports("BlazorSample.dll");

  document.getElementById("result").innerText = 
    exports.BlazorSample.Components.Pages.CallDotNet1.GetMessageFromDotnet();
}
using System.Runtime.InteropServices.JavaScript;
using System.Runtime.Versioning;

namespace BlazorSample.Pages;

[SupportedOSPlatform("browser")]
public partial class CallDotNet1
{
    [JSImport("setMessage", "CallDotNet1")]
    internal static partial void SetWelcomeMessage();

    [JSExport]
    internal static string GetMessageFromDotnet()
    {
        return "Olá do Blazor!";
    }
}

Lo spazio dei nomi dell'app per la classe parziale precedente CallDotNet1 è BlazorSample. Lo spazio dei nomi del componente è BlazorSample.Pages. Se si usa il componente precedente in un'app di test locale, aggiornare lo spazio dei nomi dell'app in modo che corrisponda all'app. Ad esempio, lo spazio dei nomi del componente è ContosoApp.Pages se lo spazio dei nomi dell'app è ContosoApp. Per altre informazioni, vedere ASP.NET Componenti di baseRazor.

Nell'esempio seguente viene importata una JS funzione denominata setMessage da un file collocato JS .

Il metodo setMessage:

  • Chiama globalThis.getDotnetRuntime(0) per esporre l'istanza di runtime .NET di WebAssembly per chiamare i metodi .NET esportati.
  • Ottiene le esportazioni dell'assembly dell'app JS . Il nome dell'assembly dell'app nell'esempio seguente è BlazorSample.
  • Chiama il BlazorSample.Pages.CallDotNet1.GetMessageFromDotnet metodo dalle esportazioni (exports). Il valore restituito, ovvero il messaggio di benvenuto, viene assegnato al CallDotNet1 testo del <span> componente. Lo spazio dei nomi dell'app è BlazorSamplee lo CallDotNet1 spazio dei nomi del componente è BlazorSample.Pages.

CallDotNet1.razor.js:

export async function setMessage() {
  const { getAssemblyExports } = await globalThis.getDotnetRuntime(0);
  var exports = await getAssemblyExports("BlazorSample.dll");

  document.getElementById("result").innerText = 
    exports.BlazorSample.Pages.CallDotNet1.GetMessageFromDotnet();
}

Nota

La chiamata getAssemblyExports a per ottenere le esportazioni può verificarsi in un inizializzatore JavaScript per la disponibilità nell'app.

Chiamate di importazione di più moduli

Dopo il caricamento di un JS modulo, le funzioni del modulo sono disponibili per i componenti e le classi dell'app JS , purché l'app sia in esecuzione nella finestra o nella scheda del browser senza ricaricare manualmente l'app. JSHost.ImportAsync può essere chiamato più volte nello stesso modulo senza una riduzione significativa delle prestazioni quando:

  • L'utente visita un componente che chiama JSHost.ImportAsync per importare un modulo, si allontana dal componente e quindi torna al componente in cui JSHost.ImportAsync viene chiamato di nuovo per la stessa importazione del modulo.
  • Lo stesso modulo viene usato da componenti diversi e caricato da JSHost.ImportAsync in ognuno dei componenti.

Uso di un singolo modulo JavaScript tra componenti

Prima di seguire le indicazioni riportate in questa sezione, leggere le sezioni Chiamare JavaScript da .NET e Chiamare .NET da JavaScript di questo articolo, che forniscono indicazioni generali sull'interoperabilità/[JSImport][JSExport].

L'esempio in questa sezione illustra come usare l'interoperabilità JS da un modulo condiviso JS in un'app lato client. Le linee guida contenute in questa sezione non sono applicabili alle Razor librerie di classi (RCL).

Vengono usati i componenti, le classi, i metodi C# e JS le funzioni seguenti:

  • Interop classe (Interop.cs): configura l'interoperabilità di importazione ed esportazione JS con gli [JSImport] attributi e [JSExport] per un modulo denominato Interop.
    • GetWelcomeMessage: metodo .NET che chiama la funzione importata getMessageJS .
    • SetWelcomeMessage: metodo .NET che chiama la funzione importata setMessageJS .
    • GetMessageFromDotnet: metodo C# esportato che restituisce una stringa di messaggio di benvenuto quando viene chiamato da JS.
  • wwwroot/js/interop.js file: contiene le JS funzioni.
    • getMessage: restituisce un messaggio di benvenuto quando viene chiamato dal codice C# in un componente.
    • setMessage: chiama il GetMessageFromDotnet metodo C# e assegna il messaggio di benvenuto restituito a un elemento DOM <span> .
  • Program.cs chiama JSHost.ImportAsync per caricare il modulo da wwwroot/js/interop.js.
  • CallJavaScript2 component (CallJavaScript2.razor): chiama GetWelcomeMessage e visualizza il messaggio di benvenuto restituito nell'interfaccia utente del componente.
  • CallDotNet2 component (CallDotNet2.razor): chiama SetWelcomeMessage.

Interop.cs:

using System.Runtime.InteropServices.JavaScript;
using System.Runtime.Versioning;

namespace BlazorSample.JavaScriptInterop;

[SupportedOSPlatform("browser")]
public partial class Interop
{
    [JSImport("getMessage", "Interop")]
    internal static partial string GetWelcomeMessage();

    [JSImport("setMessage", "Interop")]
    internal static partial void SetWelcomeMessage();

    [JSExport]
    internal static string GetMessageFromDotnet()
    {
        return "Olá do Blazor!";
    }
}

Nell'esempio precedente lo spazio dei nomi dell'app è BlazorSamplee lo spazio dei nomi completo per le classi di interoperabilità C# è BlazorSample.JavaScriptInterop.

wwwroot/js/interop.js:

export function getMessage() {
  return 'Olá do Blazor!';
}

export async function setMessage() {
  const { getAssemblyExports } = await globalThis.getDotnetRuntime(0);
  var exports = await getAssemblyExports("BlazorSample.dll");

  document.getElementById("result").innerText =
    exports.BlazorSample.JavaScriptInterop.Interop.GetMessageFromDotnet();
}

Rendere disponibile lo System.Runtime.InteropServices.JavaScript spazio dei nomi nella parte superiore del Program.cs file:

using System.Runtime.InteropServices.JavaScript;

Caricare il modulo in Program.cs prima WebAssemblyHost.RunAsync della chiamata:

if (OperatingSystem.IsBrowser())
{
    await JSHost.ImportAsync("Interop", "../js/interop.js");
}

CallJavaScript2.razor:

@page "/call-javascript-2"
@rendermode InteractiveWebAssembly
@using BlazorSample.JavaScriptInterop

<h1>
    JS <code>[JSImport]</code>/<code>[JSExport]</code> Interop 
    (Call JS Example 2)
</h1>

@(message is not null ? message : string.Empty)

@code {
    private string? message;

    protected override void OnInitialized()
    {
        message = Interop.GetWelcomeMessage();
    }
}
@page "/call-javascript-2"
@using BlazorSample.JavaScriptInterop

<h1>
    JS <code>[JSImport]</code>/<code>[JSExport]</code> Interop 
    (Call JS Example 2)
</h1>

@(message is not null ? message : string.Empty)

@code {
    private string? message;

    protected override void OnInitialized()
    {
        message = Interop.GetWelcomeMessage();
    }
}

CallDotNet2.razor:

@page "/call-dotnet-2"
@rendermode InteractiveWebAssembly
@using BlazorSample.JavaScriptInterop

<h1>
    JS <code>[JSImport]</code>/<code>[JSExport]</code> Interop  
    (Call .NET Example 2)
</h1>

<p>
    <span id="result">.NET method not executed</span>
</p>

@code {
    protected override void OnAfterRender(bool firstRender)
    {
        if (firstRender)
        {
            Interop.SetWelcomeMessage();
        }
    }
}
@page "/call-dotnet-2"
@using BlazorSample.JavaScriptInterop

<h1>
    JS <code>[JSImport]</code>/<code>[JSExport]</code> Interop  
    (Call .NET Example 2)
</h1>

<p>
    <span id="result">.NET method not executed</span>
</p>

@code {
    protected override void OnAfterRender(bool firstRender)
    {
        if (firstRender)
        {
            Interop.SetWelcomeMessage();
        }
    }
}

Importante

Nell'esempio di questa sezione viene JS usata l'interoperabilità per modificare un elemento DOM esclusivamente a scopo dimostrativo dopo il rendering del componente in OnAfterRender. In genere, è consigliabile modificare il DOM solo con JS quando l'oggetto non interagisce con Blazor. L'approccio illustrato in questa sezione è simile ai casi in cui una libreria di terze parti JS viene usata in un Razor componente, in cui il componente interagisce con la JS libreria tramite JS interoperabilità, la libreria di terze parti JS interagisce con parte del DOM e Blazor non è coinvolta direttamente con gli aggiornamenti DOM a tale parte del DOM. Per altre informazioni, vedere ASP.NET Core JavaScript interoperabilità (interoperabilità).For more information, see ASP.NET Core Blazor JavaScript interoperability (JS interop).

Risorse aggiuntive