JavaScript-Interoperabilität durch [JSImport]
/[JSExport]
mit ASP.NET Core Blazor
Hinweis
Dies ist nicht die neueste Version dieses Artikels. Informationen zum aktuellen Release finden Sie in der .NET 8-Version dieses Artikels.
Wichtig
Diese Informationen beziehen sich auf ein Vorabversionsprodukt, das vor der kommerziellen Freigabe möglicherweise noch wesentlichen Änderungen unterliegt. Microsoft gibt keine Garantie, weder ausdrücklich noch impliziert, hinsichtlich der hier bereitgestellten Informationen.
Informationen zum aktuellen Release finden Sie in der .NET 8-Version dieses Artikels.
In diesem Artikel wird erläutert, wie Sie mit der Interop-API [JSImport]
/[JSExport]
von JavaScript (JS), die für Apps mit .NET 7 oder höher veröffentlicht wurde, mit JavaScript (JS) in clientseitigen Komponenten interagieren.
Blazor bietet seinen eigenen JS-Interoperabilitätsmechanismus, der auf der IJSRuntime-Schnittstelle basiert. Die von Blazor zur Verfügung gestellte JS-Interoperabilität wird in allen Blazor-Rendermodi und für alle Blazor Hybrid-Apps einheitlich unterstützt. IJSRuntime ermöglicht Bibliotheksautoren außerdem das Erstellen von JS-Interoperabilitätsbibliotheken für die Freigabe im Blazor-Ökosystem und bleibt der empfohlene Ansatz für JS-Interoperabilität in Blazor. Weitere Informationen finden Sie in folgenden Artikeln:
- Aufrufen von JavaScript-Funktionen über .NET-Methoden in Blazor in ASP.NET Core
- Aufrufen von .NET-Methoden über JavaScript-Funktionen in Blazor in ASP.NET Core
In diesem Artikel wird ein alternativer JS-Interop-Ansatz beschrieben, der speziell für clientseitige Komponenten gilt, die in WebAssembly ausgeführt werden. Diese Ansätze eignen sich, wenn die Ausführung ausschließlich in clientseitiger WebAssembly erfolgt. Autor*innen von Bibliotheken können diese Ansätze verwenden, um die JS-Interoperabilität zu optimieren, indem sie zur Laufzeit überprüfen, ob die App in einem Browser (OperatingSystem.IsBrowser) in WebAssembly ausgeführt wird. Die in diesem Artikel beschriebenen Ansätze sollten verwendet werden, um die veraltete JS-Interop-API ohne Marshalling beim Migrieren zu .NET 7 oder höher zu ersetzen.
Hinweis
Dieser Artikel konzentriert sich auf JS-Interop in clientseitigen Komponenten. Anleitungen zum Aufrufen von .NET in JavaScript-Apps finden Sie unter Ausführen von .NET aus JavaScript.
Veraltete JavaScript-Interop-API
Die JS-Interop-API mit IJSUnmarshalledRuntime ist in ASP.NET Core in .NET 7 oder höher veraltet. Folgen Sie den Anweisungen in diesem Artikel, um die veraltete API zu ersetzen.
Voraussetzungen
Laden Sie .NET 7 oder eine höhere Version herunter, und installieren Sie die Software, wenn sie noch nicht auf dem System oder wenn auf dem System nicht die neueste Version installiert ist.
Namespace
Die in diesem Artikel beschriebene JS-Interop-API wird durch Attribute im Namespace System.Runtime.InteropServices.JavaScript gesteuert.
Aktivieren unsicherer Blöcke
Aktivieren Sie die Eigenschaft AllowUnsafeBlocks in der Projektdatei der App, damit der Codegenerator im Roslyn-Compiler Zeiger für die JS-Interoperabilität verwenden kann:
<PropertyGroup>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
Warnung
Die JS-Interop-API erfordert die Aktivierung von AllowUnsafeBlocks. Seien Sie vorsichtig, wenn Sie Ihren eigenen unsicheren Code in .NET-Anwendungen implementieren, da dies zu Sicherheits- und Stabilitätsrisiken führen kann. Weitere Informationen finden Sie unter Unsicherer Code, Zeigertypen und Funktionszeiger.
Aufrufen von JavaScript über .NET
In diesem Abschnitt wird erläutert, wie JS-Funktionen über .NET aufgerufen werden.
In der folgenden CallJavaScript1
-Komponente:
- Das
CallJavaScript1
-Modul wird mit JSHost.ImportAsync asynchron aus der verbundenenJS-Datei importiert. - Die importierte
getMessage
JS-Funktion wird vonGetWelcomeMessage
aufgerufen. - Die zurückgegebene Zeichenfolge mit der Willkommensnachricht wird über das
message
-Feld in der Benutzeroberfläche angezeigt.
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();
}
}
Hinweis
Schließen Sie in Code eine bedingte Überprüfung mit OperatingSystem.IsBrowser ein, um sicherzustellen, dass die JS-Interoperabilität nur von einer Komponente aufgerufen wird, die im Client gerendert wird. Das ist wichtig für Bibliotheken/NuGet-Pakete, die auf serverseitige Komponenten ausgerichtet sind, da sie den Code, der von dieser JS-Interop-API bereitgestellt wird, nicht ausführen können.
Wenn Sie eine JS-Funktion importieren möchten, um sie aus C# aufzurufen, verwenden Sie das [JSImport]
-Attribut für eine C#-Methodensignatur, die der Signatur der JS-Funktion entspricht. Der erste Parameter des [JSImport]
-Attributs ist der Name der zu importierenden JS-Funktion, und der zweite Parameter ist der Name des JS-Moduls.
Im folgenden Beispiel handelt es sich bei getMessage
um eine JS-Funktion, die einen Wert vom Typ string
für ein Modul namens CallJavaScript1
zurückgibt. Die C#-Methodensignatur stimmt damit überein: Es werden keine Parameter an die JS-Funktion übergeben, und die JS-Funktion gibt einen Wert vom Typ string
zurück. Die JS-Funktion wird von GetWelcomeMessage
im C#-Code aufgerufen.
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();
}
Der Namespace der App für die vorstehende Teilklasse CallJavaScript1
lautet BlazorSample
. Der Namespace der Komponente heißt BlazorSample.Components.Pages
. Wenn Sie die vorstehende Komponente in einer lokalen Test-App verwenden, aktualisieren Sie den Namespace, sodass er der App entspricht. Beispielsweise heißt der Namespace ContosoApp.Components.Pages
, wenn der Namespace der App ContosoApp
lautet. Weitere Informationen finden Sie unter Razor-Komponenten in ASP.NET Core.
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();
}
Der Namespace der App für die vorstehende Teilklasse CallJavaScript1
lautet BlazorSample
. Der Namespace der Komponente heißt BlazorSample.Pages
. Wenn Sie die vorstehende Komponente in einer lokalen Test-App verwenden, aktualisieren Sie den Namespace, sodass er der App entspricht. Beispielsweise heißt der Namespace ContosoApp.Pages
, wenn der Namespace der App ContosoApp
lautet. Weitere Informationen finden Sie unter Razor-Komponenten in ASP.NET Core.
In der importierten Methodensignatur können Sie .NET-Typen für Parameter und Rückgabewerte verwenden, die automatisch von der Laufzeit gemarshallt werden. Sie können mit JSMarshalAsAttribute<T> steuern, wie die importierten Methodenparameter gemarshallt werden. Beispielsweise können Sie entscheiden, ob ein Wert vom Typ long
als System.Runtime.InteropServices.JavaScript.JSType.Number oder System.Runtime.InteropServices.JavaScript.JSType.BigInt gemarshallt wird. Sie können Action/Func<TResult>-Rückrufe als Parameter übergeben, die als aufrufbare JS-Funktionen gemarshallt werden. Sie können sowohl JS als auch verwaltete Objektverweise übergeben. Diese werden als Proxyobjekte gemarshallt, wobei das Objekt über die Grenze hinweg aktiv bleibt, bis beim Proxy eine Garbage Collection durchgeführt wird. Zudem können asynchrone Methoden mit einem Task-Ergebnis importiert und exportiert werden. Die Ergebnisse werden als JSZusage gemarshallt. Die meisten gemarshallten Typen funktionieren sowohl bei importierten als auch bei exportierten Methoden in beiden Richtungen, als Parameter und als Rückgabewerte, die im Abschnitt Aufrufen von .NET über JavaScript weiter unten in diesem Artikel behandelt werden.
In der folgenden Tabelle werden die unterstützten Typzuordnungen aufgeführt.
.NET | JavaScript | Nullable |
Task zu Promise |
JSMarshalAs optional |
Array of |
---|---|---|---|---|---|
Boolean |
Boolean |
Unterstützt | Unterstützt | Unterstützt | Nicht unterstützt |
Byte |
Number |
Unterstützt | Unterstützt | Unterstützt | Unterstützt |
Char |
String |
Unterstützt | Unterstützt | Unterstützt | Nicht unterstützt |
Int16 |
Number |
Unterstützt | Unterstützt | Unterstützt | Nicht unterstützt |
Int32 |
Number |
Unterstützt | Unterstützt | Unterstützt | Unterstützt |
Int64 |
Number |
Unterstützt | Unterstützt | Nicht unterstützt | Nicht unterstützt |
Int64 |
BigInt |
Unterstützt | Unterstützt | Nicht unterstützt | Nicht unterstützt |
Single |
Number |
Unterstützt | Unterstützt | Unterstützt | Nicht unterstützt |
Double |
Number |
Unterstützt | Unterstützt | Unterstützt | Unterstützt |
IntPtr |
Number |
Unterstützt | Unterstützt | Unterstützt | Nicht unterstützt |
DateTime |
Date |
Unterstützt | Unterstützt | Nicht unterstützt | Nicht unterstützt |
DateTimeOffset |
Date |
Unterstützt | Unterstützt | Nicht unterstützt | Nicht unterstützt |
Exception |
Error |
Nicht unterstützt | Unterstützt | Unterstützt | Nicht unterstützt |
JSObject |
Object |
Nicht unterstützt | Unterstützt | Unterstützt | Unterstützt |
String |
String |
Nicht unterstützt | Unterstützt | Unterstützt | Unterstützt |
Object |
Any |
Nicht unterstützt | Unterstützt | Nicht unterstützt | Unterstützt |
Span<Byte> |
MemoryView |
Nicht unterstützt | Nicht unterstützt | Nicht unterstützt | Nicht unterstützt |
Span<Int32> |
MemoryView |
Nicht unterstützt | Nicht unterstützt | Nicht unterstützt | Nicht unterstützt |
Span<Double> |
MemoryView |
Nicht unterstützt | Nicht unterstützt | Nicht unterstützt | Nicht unterstützt |
ArraySegment<Byte> |
MemoryView |
Nicht unterstützt | Nicht unterstützt | Nicht unterstützt | Nicht unterstützt |
ArraySegment<Int32> |
MemoryView |
Nicht unterstützt | Nicht unterstützt | Nicht unterstützt | Nicht unterstützt |
ArraySegment<Double> |
MemoryView |
Nicht unterstützt | Nicht unterstützt | Nicht unterstützt | Nicht unterstützt |
Task |
Promise |
Nicht unterstützt | Nicht unterstützt | Unterstützt | Nicht unterstützt |
Action |
Function |
Nicht unterstützt | Nicht unterstützt | Nicht unterstützt | Nicht unterstützt |
Action<T1> |
Function |
Nicht unterstützt | Nicht unterstützt | Nicht unterstützt | Nicht unterstützt |
Action<T1, T2> |
Function |
Nicht unterstützt | Nicht unterstützt | Nicht unterstützt | Nicht unterstützt |
Action<T1, T2, T3> |
Function |
Nicht unterstützt | Nicht unterstützt | Nicht unterstützt | Nicht unterstützt |
Func<TResult> |
Function |
Nicht unterstützt | Nicht unterstützt | Nicht unterstützt | Nicht unterstützt |
Func<T1, TResult> |
Function |
Nicht unterstützt | Nicht unterstützt | Nicht unterstützt | Nicht unterstützt |
Func<T1, T2, TResult> |
Function |
Nicht unterstützt | Nicht unterstützt | Nicht unterstützt | Nicht unterstützt |
Func<T1, T2, T3, TResult> |
Function |
Nicht unterstützt | Nicht unterstützt | Nicht unterstützt | Nicht unterstützt |
Die folgenden Bedingungen gelten für Typzuordnungen und gemarshallte Werte:
- Die Spalte
Array of
gibt an, ob der .NET-Typ als JSArray
gemarshallt werden kann. Beispiel: C#int[]
(Int32
) zugeordnet zu JSArray
vonNumber
. - Wenn ein JS-Wert vom falschen Typ an C# übergeben wird, löst das Framework in den meisten Fällen eine Ausnahme aus. Das Framework führt zur Kompilierzeit keine Typüberprüfung in JS durch.
JSObject
,Exception
,Task
undArraySegment
erstellenGCHandle
und einen Proxy. Sie können die Entsorgung im Entwicklercode auslösen oder es der .NET-Garbage Collection (GC) überlassen, die Objekte später zu entfernen. Diese Typen bedeuten einen erheblichen Leistungsaufwand.Array
: Beim Marshallen eines Arrays wird eine Kopie des Arrays in JS oder .NET erstellt.MemoryView
MemoryView
ist eine JS-Klasse für die .NET-WebAssembly-Runtime zum Marshallen vonSpan
undArraySegment
.- Im Gegensatz zum Marshallen eines Arrays wird beim Marshallen einer
Span
oder einesArraySegment
keine Kopie des zugrunde liegenden Speichers erstellt. MemoryView
kann nur von der .NET-WebAssembly-Runtime ordnungsgemäß instanziiert werden. Daher ist es nicht möglich, eine JS-Funktion als .NET-Methode zu importieren, die über den ParameterSpan
oderArraySegment
verfügt.- Wenn
MemoryView
für einenSpan
erstellt wird, gilt sie nur für die Dauer des Interoperabilitätsaufrufs. DaSpan
der Aufrufliste zugewiesen wird, die nach dem Interoperabilitätsaufruf nicht beibehalten wird, ist es nicht möglich, eine .NET-Methode zu exportieren, die einenSpan
zurückgibt. MemoryView
wird für einArraySegment
erstellt und auch nach dem Interoperabilitätsaufruf beibehalten und ist damit für die gemeinsame Verwendung eines Puffers nützlich. Durch Aufrufen vondispose()
in einerMemoryView
, die für einArraySegment
erstellt wurde, wird der Proxy verworfen und das zugrunde liegende .NET-Array getrennt. Es wird empfohlen,dispose()
in einemtry-finally
-Block fürMemoryView
aufzurufen.
In der folgenden Tabelle werden die unterstützten Typzuordnungen aufgeführt.
.NET | JavaScript | Nullable |
Task zu Promise |
JSMarshalAs optional |
Array of |
---|---|---|---|---|---|
Boolean |
Boolean |
Unterstützt | Unterstützt | Unterstützt | Nicht unterstützt |
Byte |
Number |
Unterstützt | Unterstützt | Unterstützt | Unterstützt |
Char |
String |
Unterstützt | Unterstützt | Unterstützt | Nicht unterstützt |
Int16 |
Number |
Unterstützt | Unterstützt | Unterstützt | Nicht unterstützt |
Int32 |
Number |
Unterstützt | Unterstützt | Unterstützt | Unterstützt |
Int64 |
Number |
Unterstützt | Unterstützt | Nicht unterstützt | Nicht unterstützt |
Int64 |
BigInt |
Unterstützt | Unterstützt | Nicht unterstützt | Nicht unterstützt |
Single |
Number |
Unterstützt | Unterstützt | Unterstützt | Nicht unterstützt |
Double |
Number |
Unterstützt | Unterstützt | Unterstützt | Unterstützt |
IntPtr |
Number |
Unterstützt | Unterstützt | Unterstützt | Nicht unterstützt |
DateTime |
Date |
Unterstützt | Unterstützt | Nicht unterstützt | Nicht unterstützt |
DateTimeOffset |
Date |
Unterstützt | Unterstützt | Nicht unterstützt | Nicht unterstützt |
Exception |
Error |
Nicht unterstützt | Unterstützt | Unterstützt | Nicht unterstützt |
JSObject |
Object |
Nicht unterstützt | Unterstützt | Unterstützt | Unterstützt |
String |
String |
Nicht unterstützt | Unterstützt | Unterstützt | Unterstützt |
Object |
Any |
Nicht unterstützt | Unterstützt | Nicht unterstützt | Unterstützt |
Span<Byte> |
MemoryView |
Nicht unterstützt | Nicht unterstützt | Nicht unterstützt | Nicht unterstützt |
Span<Int32> |
MemoryView |
Nicht unterstützt | Nicht unterstützt | Nicht unterstützt | Nicht unterstützt |
Span<Double> |
MemoryView |
Nicht unterstützt | Nicht unterstützt | Nicht unterstützt | Nicht unterstützt |
ArraySegment<Byte> |
MemoryView |
Nicht unterstützt | Nicht unterstützt | Nicht unterstützt | Nicht unterstützt |
ArraySegment<Int32> |
MemoryView |
Nicht unterstützt | Nicht unterstützt | Nicht unterstützt | Nicht unterstützt |
ArraySegment<Double> |
MemoryView |
Nicht unterstützt | Nicht unterstützt | Nicht unterstützt | Nicht unterstützt |
Task |
Promise |
Nicht unterstützt | Nicht unterstützt | Unterstützt | Nicht unterstützt |
Action |
Function |
Nicht unterstützt | Nicht unterstützt | Nicht unterstützt | Nicht unterstützt |
Action<T1> |
Function |
Nicht unterstützt | Nicht unterstützt | Nicht unterstützt | Nicht unterstützt |
Action<T1, T2> |
Function |
Nicht unterstützt | Nicht unterstützt | Nicht unterstützt | Nicht unterstützt |
Action<T1, T2, T3> |
Function |
Nicht unterstützt | Nicht unterstützt | Nicht unterstützt | Nicht unterstützt |
Func<TResult> |
Function |
Nicht unterstützt | Nicht unterstützt | Nicht unterstützt | Nicht unterstützt |
Func<T1, TResult> |
Function |
Nicht unterstützt | Nicht unterstützt | Nicht unterstützt | Nicht unterstützt |
Func<T1, T2, TResult> |
Function |
Nicht unterstützt | Nicht unterstützt | Nicht unterstützt | Nicht unterstützt |
Func<T1, T2, T3, TResult> |
Function |
Nicht unterstützt | Nicht unterstützt | Nicht unterstützt | Nicht unterstützt |
Die folgenden Bedingungen gelten für Typzuordnungen und gemarshallte Werte:
- Die Spalte
Array of
gibt an, ob der .NET-Typ als JSArray
gemarshallt werden kann. Beispiel: C#int[]
(Int32
) zugeordnet zu JSArray
vonNumber
. - Wenn ein JS-Wert vom falschen Typ an C# übergeben wird, löst das Framework in den meisten Fällen eine Ausnahme aus. Das Framework führt zur Kompilierzeit keine Typüberprüfung in JS durch.
JSObject
,Exception
,Task
undArraySegment
erstellenGCHandle
und einen Proxy. Sie können die Entsorgung im Entwicklercode auslösen oder es der .NET-Garbage Collection (GC) überlassen, die Objekte später zu entfernen. Diese Typen bedeuten einen erheblichen Leistungsaufwand.Array
: Beim Marshallen eines Arrays wird eine Kopie des Arrays in JS oder .NET erstellt.MemoryView
MemoryView
ist eine JS-Klasse für die .NET-WebAssembly-Runtime zum Marshallen vonSpan
undArraySegment
.- Im Gegensatz zum Marshallen eines Arrays wird beim Marshallen einer
Span
oder einesArraySegment
keine Kopie des zugrunde liegenden Speichers erstellt. MemoryView
kann nur von der .NET-WebAssembly-Runtime ordnungsgemäß instanziiert werden. Daher ist es nicht möglich, eine JS-Funktion als .NET-Methode zu importieren, die über den ParameterSpan
oderArraySegment
verfügt.- Wenn
MemoryView
für einenSpan
erstellt wird, gilt sie nur für die Dauer des Interoperabilitätsaufrufs. DaSpan
der Aufrufliste zugewiesen wird, die nach dem Interoperabilitätsaufruf nicht beibehalten wird, ist es nicht möglich, eine .NET-Methode zu exportieren, die einenSpan
zurückgibt. MemoryView
wird für einArraySegment
erstellt und auch nach dem Interoperabilitätsaufruf beibehalten und ist damit für die gemeinsame Verwendung eines Puffers nützlich. Durch Aufrufen vondispose()
in einerMemoryView
, die für einArraySegment
erstellt wurde, wird der Proxy verworfen und das zugrunde liegende .NET-Array getrennt. Es wird empfohlen,dispose()
in einemtry-finally
-Block fürMemoryView
aufzurufen.
Der Modulname im [JSImport]
-Attribut und der Aufruf zum Laden des Moduls in der Komponente mit JSHost.ImportAsync müssen übereinstimmen und in der App eindeutig sein. Beim Erstellen einer Bibliothek für die Bereitstellung in einem NuGet-Paket empfehlen wir, den Namespace des NuGet-Pakets als Präfix in den Modulnamen zu verwenden. Im folgenden Beispiel spiegelt der Modulname das Contoso.InteropServices.JavaScript
-Paket und einen Ordner der Interop-Klassen für Benutzernachrichten wider (UserMessages
):
[JSImport("getMessage",
"Contoso.InteropServices.JavaScript.UserMessages.CallJavaScript1")]
Funktionen, auf die im globalen Namespace zugegriffen werden kann, können mithilfe des Präfixes globalThis
im Funktionsnamen und mithilfe des Attributs [JSImport]
ohne Angabe eines Modulnamens importiert werden. Im folgenden Beispiel hat console.log
das Präfix globalThis
. Die importierte Funktion wird von der C#-Log
Methode aufgerufen, die eine C#-Zeichenfolgenmeldung (message
) akzeptiert und die C#-Zeichenfolge in einen JSString
für console.log
marshallt:
[JSImport("globalThis.console.log")]
internal static partial void Log([JSMarshalAs<JSType.String>] string message);
Exportieren Sie Skripts aus einem standardmäßigen JavaScript ES6-Modul, das entweder mit einer Komponente verbunden ist oder mit anderen statischen JavaScript-Ressourcen in einer JS-Datei platziert wird (z. B. wwwroot/js/{FILE NAME}.js
, wobei statische JS-Ressourcen in einem Ordner namens js
im Ordner wwwroot
der App verwaltet werden und der Platzhalter {FILE NAME}
für den Dateinamen steht).
Im folgenden Beispiel wird eine JS-Funktion namens getMessage
aus einer verbundenen JS-Datei exportiert, die die Willkommensnachricht „Hello from Blazor!“ in Portugiesisch zurückgibt:
CallJavaScript1.razor.js
:
export function getMessage() {
return 'Olá do Blazor!';
}
Aufrufen von .NET über JavaScript
In diesem Abschnitt wird erläutert, wie Sie .NET-Methoden über JSaufrufen.
Die folgende CallDotNet1
-Komponente ruft JS auf, das direkt mit dem DOM interagiert, um die Zeichenfolge mit der Willkommensnachricht zu rendern:
- Das
CallDotNet
JS-Modul wird asynchron aus der verbundenen JS-Datei für diese Komponente importiert. - Die importierte
setMessage
JS-Funktion wird vonSetWelcomeMessage
aufgerufen. - Die zurückgegebene Willkommensnachricht wird von
setMessage
über dasmessage
-Feld in der Benutzeroberfläche angezeigt.
Wichtig
Im Beispiel dieses Abschnitts wird die JS-Interoperabilität verwendet, um ein DOM-Element rein zu Demonstrationszwecken zu mutieren, nachdem die Komponente in OnAfterRender
gerendert wurde. Normalerweise sollten Sie das DOM mit JS nur mutieren, wenn das Objekt nicht mit Blazor interagiert. Der in diesem Abschnitt gezeigte Ansatz ähnelt Fällen, in denen eine JS-Bibliothek von einem Drittanbieter in einer Razor-Komponente verwendet wird, wobei die Komponente über JS-Interoperabilität mit der JS-Bibliothek interagiert, die JS-Bibliothek des Drittanbieters mit einem Teil des DOM interagiert und Blazor nicht direkt an den DOM-Updates für diesen Teil des DOM beteiligt ist. Weitere Informationen finden Sie unter JavaScript-Interoperabilität von Blazor in ASP.NET Core (JS-Interoperabilität).
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();
}
}
}
Verwenden Sie das [JSExport]
-Attribut, um eine .NET-Methode zu exportieren, damit sie über JS aufgerufen werden kann.
Im folgenden Beispiel:
SetWelcomeMessage
ruft eine JS-Funktion mit dem NamensetMessage
auf. Die JS-Funktion ruft .NET auf, um die Willkommensnachricht vonGetMessageFromDotnet
zu empfangen, und zeigt die Nachricht in der Benutzeroberfläche an.GetMessageFromDotnet
ist eine .NET-Methode mit dem[JSExport]
-Attribut, das die Willkommensnachricht „Hello from Blazor!“ in Portugiesisch zurückgibt.
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!";
}
}
Der Namespace der App für die vorstehende Teilklasse CallDotNet1
lautet BlazorSample
. Der Namespace der Komponente heißt BlazorSample.Components.Pages
. Wenn Sie die vorstehende Komponente in einer lokalen Test-App verwenden, aktualisieren Sie deren Namespace, sodass er der App entspricht. Beispielsweise heißt der Namespace der Komponente ContosoApp.Components.Pages
, wenn der Namespace der App ContosoApp
lautet. Weitere Informationen finden Sie unter Razor-Komponenten in ASP.NET Core.
Im folgenden Beispiel wird eine JS-Funktion namens setMessage
aus einer verbundenen JS-Datei importiert.
Die setMessage
-Methode:
- Ruft
globalThis.getDotnetRuntime(0)
auf, um die WebAssembly .NET-Laufzeitinstanz für das Aufrufen exportierter .NET-Methoden verfügbar zu machen. - Ruft die JS-Exporte der App-Assembly ab. Der Name der App-Assembly lautet im folgenden Beispiel
BlazorSample
. - Ruft die
BlazorSample.Components.Pages.CallDotNet1.GetMessageFromDotnet
-Methode aus den Exporten (exports
) auf. Der zurückgegebene Wert, der die Willkommensnachricht enthält, wird dem<span>
-Text derCallDotNet1
-Komponente zugewiesen. Der Namespace der App lautetBlazorSample
, und der Namespace derCallDotNet1
-Komponente heißtBlazorSample.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!";
}
}
Der Namespace der App für die vorstehende Teilklasse CallDotNet1
lautet BlazorSample
. Der Namespace der Komponente heißt BlazorSample.Pages
. Wenn Sie die vorstehende Komponente in einer lokalen Test-App verwenden, aktualisieren Sie deren Namespace, sodass er der App entspricht. Beispielsweise heißt der Namespace der Komponente ContosoApp.Pages
, wenn der Namespace der App ContosoApp
lautet. Weitere Informationen finden Sie unter Razor-Komponenten in ASP.NET Core.
Im folgenden Beispiel wird eine JS-Funktion namens setMessage
aus einer verbundenen JS-Datei importiert.
Die setMessage
-Methode:
- Ruft
globalThis.getDotnetRuntime(0)
auf, um die WebAssembly .NET-Laufzeitinstanz für das Aufrufen exportierter .NET-Methoden verfügbar zu machen. - Ruft die JS-Exporte der App-Assembly ab. Der Name der App-Assembly lautet im folgenden Beispiel
BlazorSample
. - Ruft die
BlazorSample.Pages.CallDotNet1.GetMessageFromDotnet
-Methode aus den Exporten (exports
) auf. Der zurückgegebene Wert, der die Willkommensnachricht enthält, wird dem<span>
-Text derCallDotNet1
-Komponente zugewiesen. Der Namespace der App lautetBlazorSample
, und der Namespace derCallDotNet1
-Komponente heißtBlazorSample.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();
}
Hinweis
Aufrufe von getAssemblyExports
zum Abrufen der Exporte können in einem JavaScript-Initialisierer erfolgen, damit sie in der gesamten App verfügbar sind.
Mehrere Modulimportaufrufe
Nachdem ein JS-Modul geladen wurde, sind die JS-Funktionen des Moduls für die Komponenten und Klassen der App verfügbar, solange die App im Browserfenster oder auf einer Registerkarte ausgeführt wird, ohne dass der Benutzer die App manuell neu lädt. JSHost.ImportAsync kann ohne erhebliche Leistungseinbußen mehrmals für dasselbe Modul aufgerufen werden, wenn Folgendes gilt:
- Der Benutzer besucht eine Komponente, die zum Importieren eines Moduls JSHost.ImportAsync aufruft, er navigiert von der Komponente weg und kehrt später zur Komponente zurück, wobei JSHost.ImportAsync erneut für den gleichen Modulimport aufgerufen wird.
- Dasselbe Modul wird von verschiedenen Komponenten verwendet und von JSHost.ImportAsync in jede dieser Komponenten geladen.
Verwenden eines einzelnen JavaScript-Moduls für verschiedene Komponenten
Bevor Sie die Anleitungen in diesem Abschnitt befolgen, sollten Sie die Abschnitte Aufrufen von JavaScript über .NET und Aufrufen von .NET über JavaScript dieses Artikels lesen, die allgemeine Anleitungen zur [JSImport]
/[JSExport]
-Interoperabilität bereitstellen.
Das Beispiel in diesem Abschnitt zeigt, wie Sie JS-Interoperabilität über ein freigegebenes JS-Modul in einer clientseitigen App verwenden. Die Anleitungen in diesem Abschnitt gelten nicht für Razor-Klassenbibliotheken (RCLs).
Die folgenden Komponenten, Klassen, C#-Methoden und JS-Funktionen werden verwendet:
Interop
-Klasse (Interop.cs
): Richtet mit den Attributen[JSImport]
und[JSExport]
für ein Modul namensInterop
JS-Interoperabilität zum Importieren und Exportieren ein.GetWelcomeMessage
: .NET-Methode, die die importiertegetMessage
JS-Funktion aufruft.SetWelcomeMessage
: .NET-Methode, die die importiertesetMessage
JS-Funktion aufruft.GetMessageFromDotnet
: Eine exportierte C#-Methode, die eine Zeichenfolge mit einer Willkommensnachricht zurückgibt, wenn sie über JS aufgerufen wird.
wwwroot/js/interop.js
-Datei: Enthält die JS-Funktionen.getMessage
: Gibt eine Willkommensnachricht zurück, wenn sie von C#-Code in einer Komponente aufgerufen wird.setMessage
: Ruft die C#-MethodeGetMessageFromDotnet
auf und weist die zurückgegebene Willkommensnachricht einem DOM-Element<span>
zu.
Program.cs
ruft JSHost.ImportAsync aus, um das Moduls auswwwroot/js/interop.js
zu laden.CallJavaScript2
-Komponente (CallJavaScript2.razor
): RuftGetWelcomeMessage
auf und zeigt die zurückgegebene Willkommensnachricht in der Benutzeroberfläche der Komponente an.CallDotNet2
Komponente (CallDotNet2.razor
): RuftSetWelcomeMessage
auf.
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!";
}
}
Im vorherigen Beispiel lautet der Namespace der App BlazorSample
, und der vollständige Namespace für C#-Interoperabilitätsklassen lautet 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();
}
Machen Sie den Namespace System.Runtime.InteropServices.JavaScript am Anfang der Program.cs
-Datei verfügbar:
using System.Runtime.InteropServices.JavaScript;
Laden Sie das Modul in Program.cs
, bevor WebAssemblyHost.RunAsync aufgerufen wird:
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();
}
}
}
Wichtig
Im Beispiel dieses Abschnitts wird die JS-Interoperabilität verwendet, um ein DOM-Element rein zu Demonstrationszwecken zu mutieren, nachdem die Komponente in OnAfterRender
gerendert wurde. Normalerweise sollten Sie das DOM mit JS nur mutieren, wenn das Objekt nicht mit Blazor interagiert. Der in diesem Abschnitt gezeigte Ansatz ähnelt Fällen, in denen eine JS-Bibliothek von einem Drittanbieter in einer Razor-Komponente verwendet wird, wobei die Komponente über JS-Interoperabilität mit der JS-Bibliothek interagiert, die JS-Bibliothek des Drittanbieters mit einem Teil des DOM interagiert und Blazor nicht direkt an den DOM-Updates für diesen Teil des DOM beteiligt ist. Weitere Informationen finden Sie unter JavaScript-Interoperabilität von Blazor in ASP.NET Core (JS-Interoperabilität).
Zusätzliche Ressourcen
- API-Dokumentation
- Ausführen von .NET aus JavaScript
- Im GitHub-Repository
dotnet/runtime
:
Feedback
https://aka.ms/ContentUserFeedback.
Bald verfügbar: Im Laufe des Jahres 2024 werden wir GitHub-Issues stufenweise als Feedbackmechanismus für Inhalte abbauen und durch ein neues Feedbacksystem ersetzen. Weitere Informationen finden Sie unterFeedback senden und anzeigen für