Interoperabilità JavaScript [JSImport]
/[JSExport]
Nota
Questa non è la versione più recente di questo articolo. Per la versione corrente, vedere la versione .NET 8 di questo articolo.
Avviso
Questa versione di ASP.NET Core non è più supportata. Per altre informazioni, vedere Criteri di supporto di .NET e .NET Core. 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 eseguire .NET da JavaScript (JS) usando/JS[JSImport]
[JSExport]
l'interoperabilità.
Per altre indicazioni, vedere le indicazioni sulla configurazione e l'hosting di applicazioni WebAssembly .NET nel repository GitHub .NET Runtime (dotnet/runtime
).
Le app esistenti JS possono usare il supporto WebAssembly lato client espanso per riutilizzare le librerie .NET da JS o per creare un nuovo . App e framework basati su NET.
Nota
Questo articolo è incentrato sull'esecuzione di .NET da JS app senza alcuna dipendenza da Blazor. Per indicazioni sull'uso dell'interoperabilità nelle app, vedere Interoperabilità JSImport/JSExport JavaScript con ASP.NET CoreBlazor.Blazor WebAssembly [JSImport]
/[JSExport]
Questi approcci sono appropriati quando si prevede di eseguire solo in WebAssembly (WASM). Le librerie possono eseguire un controllo di runtime per determinare se l'app è in esecuzione WASM chiamando OperatingSystem.IsBrowser.
Prerequisiti
.NET SDK (versione più recente)
Installare il wasm-tools
carico di lavoro in una shell dei comandi amministrativa, che include le destinazioni MSBuild correlate:
dotnet workload install wasm-tools
Gli strumenti possono essere installati anche tramite il programma di installazione di Visual Studio nel carico di lavoro ASP.NET e sviluppo Web nel programma di installazione di Visual Studio. Selezionare l'opzione Strumenti di compilazione WebAssembly .NET dall'elenco dei componenti facoltativi.
Facoltativamente, installare il wasm-experimental
carico di lavoro, che contiene modelli di progetto sperimentali per iniziare a usare .NET in WebAssembly in un'app browser (App WebAssembly Browser) o in un nodo.jsApp console basata su -based (App console WebAssembly). Questo carico di lavoro non è necessario se si prevede di integrare JS[JSExport]
[JSImport]
/l'interoperabilità in un'app esistente.JS
dotnet workload install wasm-experimental
I modelli possono essere installati anche dal Microsoft.NET.Runtime.WebAssembly.Templates
pacchetto NuGet con il comando seguente:
dotnet new install Microsoft.NET.Runtime.WebAssembly.Templates
Per altre informazioni, vedere la sezione Modelli di progetto e carico di lavoro sperimentale.
Spazio dei nomi
L'API JS di interoperabilità descritta in questo articolo è controllata dagli attributi nello spazio dei System.Runtime.InteropServices.JavaScript nomi .
Configurazione del progetto
Per configurare un progetto (.csproj
) per abilitare JS l'interoperabilità:
Impostare il moniker del framework di destinazione (
{TARGET FRAMEWORK}
segnaposto):<TargetFramework>{TARGET FRAMEWORK}</TargetFramework>
È supportato .NET 7 (
net7.0
) o versione successiva.Abilitare la AllowUnsafeBlocks proprietà , che consente al generatore di codice nel compilatore Roslyn di usare i puntatori per JS l'interoperabilità:
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
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.
Di seguito è riportato un file di progetto di esempio (.csproj
) dopo la configurazione. Il {TARGET FRAMEWORK}
segnaposto è il framework di destinazione:
<Project Sdk="Microsoft.NET.Sdk.WebAssembly">
<PropertyGroup>
<TargetFramework>{TARGET FRAMEWORK}</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
</Project>
Impostare il moniker del framework di destinazione:
<TargetFramework>net7.0</TargetFramework>
È supportato .NET 7 (
net7.0
) o versione successiva.Specificare
browser-wasm
per l'identificatore di runtime:<RuntimeIdentifier>browser-wasm</RuntimeIdentifier>
Specificare un tipo di output eseguibile:
<OutputType>Exe</OutputType>
Abilitare la AllowUnsafeBlocks proprietà , che consente al generatore di codice nel compilatore Roslyn di usare i puntatori per JS l'interoperabilità:
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
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.
Specificare
WasmMainJSPath
per puntare a un file su disco. Questo file viene pubblicato con l'app, ma l'uso del file non è necessario se si sta integrando .NET in un'app esistente JS .Nell'esempio seguente il JS file su disco è
main.js
, ma qualsiasi JS nome file è consentito:<WasmMainJSPath>main.js</WasmMainJSPath>
File di progetto di esempio (.csproj
) dopo la configurazione:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<RuntimeIdentifier>browser-wasm</RuntimeIdentifier>
<OutputType>Exe</OutputType>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<WasmMainJSPath>main.js</WasmMainJSPath>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
Interoperabilità JavaScript in WASM
Le API nell'esempio seguente vengono importate da dotnet.js
. Queste API consentono di configurare moduli denominati che possono essere importati nel codice C# e chiamare i metodi esposti dal codice .NET, incluso Program.Main
.
Importante
"Importazione" ed "esportazione" in questo articolo vengono definiti dal punto di vista di .NET:
- Un'app importa metodi JS in modo che possano essere chiamati da .NET.
- L'app esporta metodi .NET in modo che possano essere chiamati da JS.
Nell'esempio seguente :
Il
dotnet.js
file viene usato per creare e avviare il runtime .NET WebAssembly.dotnet.js
viene generato come parte dell'output di compilazione dell'app.Importante
Per eseguire l'integrazione con un'app esistente, copiare il contenuto della cartella di output di pubblicazione† negli asset di distribuzione dell'app esistente in modo che possa essere servita insieme all'oggetto rest dell'app. Per le distribuzioni di produzione, pubblicare l'app con il
dotnet publish -c Release
comando in una shell dei comandi e distribuire il contenuto della cartella di output con l'app.†La cartella di output di pubblicazione è il percorso di destinazione del profilo di pubblicazione. Il valore predefinito per un Release profilo in .NET 8 o versione successiva è
bin/Release/{TARGET FRAMEWORK}/publish
, dove il{TARGET FRAMEWORK}
segnaposto è il framework di destinazione , ad esempionet8.0
.dotnet.create()
configura il runtime .NET WebAssembly.
setModuleImports
associa un nome a un modulo di JS funzioni per l'importazione in .NET. Il JS modulo contiene unadom.setInnerText
funzione, che accetta e il selettore di elementi e il tempo per visualizzare l'ora del controllo di arresto corrente nell'interfaccia utente. Il nome del modulo può essere qualsiasi stringa (non deve essere un nome di file), ma deve corrispondere al nome usato con (JSImportAttribute
illustrato più avanti in questo articolo). Ladom.setInnerText
funzione viene importata in C# e chiamata dal metodoSetInnerText
C# . IlSetInnerText
metodo viene illustrato più avanti in questa sezione.exports.StopwatchSample.Reset()
chiama in .NET (StopwatchSample.Reset
) da JS. IlReset
metodo C# riavvia il controllo di arresto se è in esecuzione o lo reimposta se non è in esecuzione. IlReset
metodo viene illustrato più avanti in questa sezione.exports.StopwatchSample.Toggle()
chiama in .NET (StopwatchSample.Toggle
) da JS. IlToggle
metodo C# avvia o arresta il controllo di arresto a seconda che sia in esecuzione o meno. IlToggle
metodo viene illustrato più avanti in questa sezione.runMain()
esegueProgram.Main
.
setModuleImports
associa un nome a un modulo di JS funzioni per l'importazione in .NET. Il JS modulo contiene unawindow.location.href
funzione che restituisce l'indirizzo di pagina corrente (URL). Il nome del modulo può essere qualsiasi stringa (non deve essere un nome di file), ma deve corrispondere al nome usato con (JSImportAttribute
illustrato più avanti in questo articolo). Lawindow.location.href
funzione viene importata in C# e chiamata dal metodoGetHRef
C# . IlGetHRef
metodo viene illustrato più avanti in questa sezione.exports.MyClass.Greeting()
chiama in .NET (MyClass.Greeting
) da JS. IlGreeting
metodo C# restituisce una stringa che include il risultato della chiamata allawindow.location.href
funzione. IlGreeting
metodo viene illustrato più avanti in questa sezione.dotnet.run()
esegueProgram.Main
.
JS modulo:
import { dotnet } from './_framework/dotnet.js'
const { setModuleImports, getAssemblyExports, getConfig, runMain } = await dotnet
.withApplicationArguments("start")
.create();
setModuleImports('main.js', {
dom: {
setInnerText: (selector, time) =>
document.querySelector(selector).innerText = time
}
});
const config = getConfig();
const exports = await getAssemblyExports(config.mainAssemblyName);
document.getElementById('reset').addEventListener('click', e => {
exports.StopwatchSample.Reset();
e.preventDefault();
});
const pauseButton = document.getElementById('pause');
pauseButton.addEventListener('click', e => {
const isRunning = exports.StopwatchSample.Toggle();
pauseButton.innerText = isRunning ? 'Pause' : 'Start';
e.preventDefault();
});
await runMain();
import { dotnet } from './_framework/dotnet.js'
const { setModuleImports, getAssemblyExports, getConfig } = await dotnet
.withDiagnosticTracing(false)
.withApplicationArgumentsFromQuery()
.create();
setModuleImports('main.js', {
window: {
location: {
href: () => globalThis.window.location.href
}
}
});
const config = getConfig();
const exports = await getAssemblyExports(config.mainAssemblyName);
const text = exports.MyClass.Greeting();
console.log(text);
document.getElementById('out').innerHTML = text;
await dotnet.run();
import { dotnet } from './dotnet.js'
const is_browser = typeof window != "undefined";
if (!is_browser) throw new Error(`Expected to be running in a browser`);
const { setModuleImports, getAssemblyExports, getConfig } =
await dotnet.create();
setModuleImports("main.js", {
window: {
location: {
href: () => globalThis.window.location.href
}
}
});
const config = getConfig();
const exports = await getAssemblyExports(config.mainAssemblyName);
const text = exports.MyClass.Greeting();
console.log(text);
document.getElementById("out").innerHTML = text;
await dotnet.run();
Per importare una JS funzione in modo che possa essere chiamata da C#, usare il nuovo JSImportAttribute oggetto in una firma del metodo corrispondente. Il primo parametro di JSImportAttribute è il nome della JS funzione da importare e il secondo parametro è il nome del modulo.
Nell'esempio seguente la dom.setInnerText
funzione viene chiamata dal modulo quando SetInnerText
viene chiamato il main.js
metodo :
[JSImport("dom.setInnerText", "main.js")]
internal static partial void SetInnerText(string selector, string content);
Nell'esempio seguente la window.location.href
funzione viene chiamata dal modulo quando GetHRef
viene chiamato il main.js
metodo :
[JSImport("window.location.href", "main.js")]
internal static partial string GetHRef();
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.
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);
Per esportare un metodo .NET in modo che possa essere chiamato da JS, usare .JSExportAttribute
Nell'esempio seguente ogni metodo viene esportato in JS e può essere chiamato da JS funzioni:
- Il
Toggle
metodo avvia o arresta il controllo di arresto a seconda dello stato di esecuzione. - Il
Reset
metodo riavvia il controllo di arresto se è in esecuzione o lo reimposta se non è in esecuzione. - Il
IsRunning
metodo indica se il controllo di arresto è in esecuzione.
[JSExport]
internal static bool Toggle()
{
if (stopwatch.IsRunning)
{
stopwatch.Stop();
return false;
}
else
{
stopwatch.Start();
return true;
}
}
[JSExport]
internal static void Reset()
{
if (stopwatch.IsRunning)
stopwatch.Restart();
else
stopwatch.Reset();
Render();
}
[JSExport]
internal static bool IsRunning() => stopwatch.IsRunning;
Nell'esempio seguente il Greeting
metodo restituisce una stringa che include il risultato della chiamata al GetHRef
metodo . Come illustrato in precedenza, il GetHref
metodo C# chiama per JS la window.location.href
funzione dal main.js
modulo. window.location.href
restituisce l'indirizzo di pagina corrente (URL):
[JSExport]
internal static string Greeting()
{
var text = $"Hello, World! Greetings from {GetHRef()}";
Console.WriteLine(text);
return text;
}
Carichi di lavoro sperimentali e modelli di progetto
Per illustrare la JS funzionalità di interoperabilità e ottenere JS modelli di progetto di interoperabilità, installare il wasm-experimental
carico di lavoro:
dotnet workload install wasm-experimental
Il wasm-experimental
carico di lavoro contiene due modelli di progetto: wasmbrowser
e wasmconsole
. Questi modelli sono sperimentali in questo momento, il che significa che il flusso di lavoro per gli sviluppatori per i modelli è in continua evoluzione. Tuttavia, le API e JS .NET usate nei modelli sono supportate in .NET 8 e forniscono una base per l'uso di .NET in WASM da JS.
I modelli possono essere installati anche dal Microsoft.NET.Runtime.WebAssembly.Templates
pacchetto NuGet con il comando seguente:
dotnet new install Microsoft.NET.Runtime.WebAssembly.Templates
App browser
È possibile creare un'app browser con il wasmbrowser
modello dalla riga di comando, che crea un'app Web che illustra l'uso di .NET e JS insieme in un browser:
dotnet new wasmbrowser
In alternativa, in Visual Studio è possibile creare l'app usando il modello di WebAssembly Browser App progetto.
Compilare l'app da Visual Studio o usando l'interfaccia della riga di comando di .NET:
dotnet build
Compilare ed eseguire l'app da Visual Studio o usando l'interfaccia della riga di comando di .NET:
dotnet run
In alternativa, installare e usare il dotnet serve
comando :
dotnet serve -d:bin/$(Configuration)/{TARGET FRAMEWORK}/publish
Nell'esempio precedente il {TARGET FRAMEWORK}
segnaposto è il moniker del framework di destinazione.
Nodo.js app console
È possibile creare un'app console con il wasmconsole
modello , che crea un'app eseguita WASM in come app console Node o js V8:
dotnet new wasmconsole
In alternativa, in Visual Studio è possibile creare l'app usando il modello di WebAssembly Console App progetto.
Compilare l'app da Visual Studio o usando l'interfaccia della riga di comando di .NET:
dotnet build
Compilare ed eseguire l'app da Visual Studio o usando l'interfaccia della riga di comando di .NET:
dotnet run
In alternativa, avviare qualsiasi file server statico dalla directory di output di pubblicazione che contiene il main.mjs
file:
node bin/$(Configuration)/{TARGET FRAMEWORK}/{PATH}/main.mjs
Nell'esempio precedente il {TARGET FRAMEWORK}
segnaposto è il moniker del framework di destinazione e il {PATH}
segnaposto è il percorso del main.mjs
file.
Risorse aggiuntive
- Configurazione e hosting di applicazioni WebAssembly .NET
- Documentazione dell'API
- Interoperabilità JSImport/JSExport JavaScript con ASP.NET Core Blazor
dotnet/runtime
Nel repository GitHub:- Usare .NET da qualsiasi app JavaScript in .NET 7