JavaScript-Interoperabilität von Blazor in ASP.NET Core (JS-Interoperabilität)
Hinweis
Dies ist nicht die neueste Version dieses Artikels. Informationen zum aktuellen Release finden Sie in der .NET 8-Version dieses Artikels.
Warnung
Diese Version von ASP.NET Core wird nicht mehr unterstützt. Weitere Informationen finden Sie in der Supportrichtlinie für .NET und .NET Core. 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.
Eine Blazor-App kann JavaScript-(JS)-Funktionen über .NET-Methoden und .NET-Methoden über JS-Funktionen aufrufen. Diese Szenarien werden als JavaScript-Interoperabilität (JS Interop) bezeichnet.
Weitere JS-Interop-Anleitungen finden Sie in den 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
Hinweis
Die JavaScript-Interop-API [JSImport]
/[JSExport]
ist für clientseitige Komponenten in ASP.NET Core in .NET 7 oder höher verfügbar.
Weitere Informationen finden Sie unter JavaScript-Interoperabilität mit JSImport/JSExport mit ASP.NET CoreBlazor.
Komprimierung für interaktive Serverkomponenten mit nicht vertrauenswürdigen Daten
Mit standardmäßiger aktivierter Komprimierung vermeiden Sie die Erstellung sicherer (authentifizierter/autorisierter) serverseitiger Komponenten, die Daten aus nicht vertrauenswürdigen Quellen rendern. Nicht vertrauenswürdige Quellen umfassen Routenparameter, Abfragezeichenfolgen, Daten aus JS-Interoperabilität und andere Datenquellen, die ein Drittbenutzer steuern kann (Datenbanken, externe Dienste). Weitere Informationen finden Sie unter ASP.NET Core BlazorSignalR Anleitungen und Anleitung zur Risikominderung für ASP.NET Core Blazor interaktives serverseitiges Rendering.
Paket mit JavaScript-Interop-Abstraktionen und -Features
Das Paket @microsoft/dotnet-js-interop
(npmjs.com
) (NuGet-Paket Microsoft.JSInterop
) enthält Abstraktionen und Features für die Interoperabilität zwischen .NET- und JavaScript-Code (JS). Die Referenzquelle finden Sie im GitHub-Repository dotnet/aspnetcore
(im Ordner /src/JSInterop
). Weitere Informationen finden Sie im GitHub-Repository in der Datei README.md
.
Hinweis
Dokumentationslinks zur .NET-Referenzquelle laden in der Regel den Standardbranch des Repositorys, der die aktuelle Entwicklung für das nächste Release von .NET darstellt. Um ein Tag für ein bestimmtes Release auszuwählen, wählen Sie diesen mit der Dropdownliste Switch branches or tags (Branches oder Tags wechseln) aus. Weitere Informationen finden Sie unter How to select a version tag of ASP.NET Core source code (dotnet/AspNetCore.Docs #26205) (Auswählen eines Versionstags von ASP.NET Core-Quellcode (dotnet/AspNetCore.Docs #26205)).
Weitere Ressourcen zum Schreiben von JS-Interop-Skripts in TypeScript:
- TypeScript
- Tutorial: Erstellen einer ASP.NET Core-App mit TypeScript in Visual Studio
- Verwalten von NPM-Paketen in Visual Studio
Interaktion mit dem DOM
Mutieren Sie das DOM nur mit JavaScript (JS), wenn das Objekt nicht mit Blazor interagiert. Blazor verwaltet Darstellungen des DOM und interagiert direkt mit DOM-Objekten. Wenn ein von Blazor gerendertes Element extern mithilfe von JS direkt oder über JS-Interop geändert wird, stimmt das DOM möglicherweise nicht mehr der internen Darstellung von Blazor überein, sodass es zu einem undefinierte Verhalten kommen kann. Ein undefiniertes Verhalten kann lediglich die Darstellung von Elementen oder deren Funktionen beeinträchtigen, aber auch Sicherheitsrisiken für die App oder den Server mit sich bringen.
Diese Anleitung gilt nicht nur für Ihren eigenen JS-Interop-Code, sondern auch für alle JS-Bibliotheken, die von der App verwendet werden, einschließlich aller von einem Drittanbieterframework bereitgestellten Inhalte wie Bootstrap JS und jQuery.
In einigen Dokumentationsbeispielen wird JS-Interop verwendet, um ein Element als Teil eines Beispiels lediglich zu Demonstrationszwecken zu mutieren. In diesen Fällen wird im Text eine Warnung angezeigt.
Weitere Informationen finden Sie unter Aufrufen von JavaScript-Funktionen über .NET-Methoden in Blazor in ASP.NET Core.
JavaScript-Klasse mit einem Feld vom Typ „Funktion“
Eine JavaScript-Klasse mit einem Feld vom Typ „Funktion“ wird nicht von BlazorJS Interop unterstützt. Verwenden Sie Javascript-Funktionen in Klassen.
Nicht unterstützt:GreetingHelpers.sayHello
wird in der folgenden Klasse als Feld vom Typ „Funktion“ von JS Interop von Blazor nicht erkannt und kann nicht von C#-Code aus ausgeführt werden:
export class GreetingHelpers {
sayHello = function() {
...
}
}
Unterstützt:GreetingHelpers.sayHello
wird in der folgenden Klasse als Funktion unterstützt:
export class GreetingHelpers {
sayHello() {
...
}
}
Pfeilfunktionen werden ebenfalls unterstützt:
export class GreetingHelpers {
sayHello = () => {
...
}
}
Vermeiden von Inlineereignishandlern
Eine JavaScript-Funktion kann direkt aus einem Inlineereignishandler aufgerufen werden. Im folgenden Beispiel ist alertUser
eine JavaScript-Funktion, die aufgerufen wird, wenn die Schaltfläche von den Benutzenden ausgewählt wird:
<button onclick="alertUser">Click Me!</button>
Die Verwendung von Inlineereignishandlern ist jedoch eine schlechte Designentscheidung für den Aufruf von JavaScript-Funktionen:
- Die Vermischung von HTML-Markup und JavaScript-Code führt oft zu nicht wartbarem Code.
- Die Ausführung des Inlineereignishandlers kann durch eine Richtlinie für Inhaltssicherheit (Content Security Policy, CSP) (MDN-Dokumentation) blockiert werden.
Es wird empfohlen, Inlineereignishandler zu vermeiden und stattdessen Ansätze zu verwenden, bei denen Handler in JavaScript mit addEventListener
zugewiesen werden, wie das folgende Beispiel zeigt:
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)
{
await module.DisposeAsync();
}
}
}
Weitere Informationen finden Sie in den folgenden Ressourcen:
Asynchrone JavaScript-Aufrufe
JS-Interop-Aufrufe sind standardmäßig asynchron, und zwar unabhängig davon, ob der aufgerufene Code synchron oder asynchron ist. Aufrufe sind standardmäßig asynchron, um sicherzustellen, dass Komponenten mit serverseitigen und clientseitigen Renderingmodellen kompatibel sind. Bei Verwendung von serverseitigem Rendering müssen JS-Interop-Aufrufe asynchron sein, da sie über eine Netzwerkverbindung gesendet werden. Für Apps, die ausschließlich clientseitiges Rendering verwenden, werden synchrone JS-Interop-Aufrufe unterstützt.
Weitere Informationen finden Sie in den folgenden Artikeln:
Weitere Informationen finden Sie unter Aufrufen von JavaScript-Funktionen über .NET-Methoden in Blazor in ASP.NET Core.
Objektserialisierung
Blazor verwendet System.Text.Json für die Serialisierung. Dabei gelten die folgenden Anforderungen und Standardverhalten:
- Typen müssen über einen Standardkonstruktor verfügen,
get
/set
-Zugriffsmethoden müssen öffentlich sein, und Felder werden nie serialisiert. - Die globale Standardserialisierung kann nicht angepasst werden, damit vorhandene Komponentenbibliotheken ihre Funktionalität nicht verlieren, die Leistung und Sicherheit nicht beeinträchtigt werden und die Zuverlässigkeit nicht verringert wird.
- Das Serialisieren von .NET-Membernamen führt zu JSON-Schlüsselnamen in Kleinbuchstaben.
- JSON-Code wird als JsonElement-C#-Instanzen deserialisiert, wodurch eine gemischte Groß- und Kleinschreibung zulässig wird. Die interne Umwandlung für die Zuweisung zu C#-Modelleigenschaften funktioniert trotz aller Unterschiede zwischen JSON-Schlüsselnamen und C#-Eigenschaftsnamen erwartungsgemäß.
- Komplexe Frameworktypen, wie z. B. KeyValuePair können vom IL Trimmer beim Veröffentlichen entfernt und nicht für die JS-Interoperabilität vorhanden sein. Es wird empfohlen, benutzerdefinierte Typen für Typen zu erstellen, die der IL Trimmer standardmäßig entfernt.
- Blazor basiert immer auf Reflexion für die JSON-Serialisierung, einschließlich der Verwendung der C#-Quellgenerierung. Das Festlegen von
JsonSerializerIsReflectionEnabledByDefault
auffalse
in der Projektdatei der App führt zu einem Fehler, wenn versucht wird, die Serialisierung durchzuführen.
Die benutzerdefinierte Serialisierung der JsonConverter-API ist möglich. Eigenschaften können mit einem [JsonConverter]
-Attribut versehen werden, um die Standardserialisierung eines vorhandenen Datentyps zu überschreiben.
Weitere Informationen finden Sie in den folgenden Ressourcen der .NET-Dokumentation:
- JSON-Serialisierung und -Deserialisierung (Marshalling und Rückgängigmachen von Marshalling) in .NET
- Anpassen von Eigenschaftsnamen und -werten mit
System.Text.Json
- Schreiben von benutzerdefinierten Konvertern für die JSON-Serialisierung (Marshallen) in .NET
Blazor unterstützt optimiertes Bytearray-JS-Interop, mit dem sich das Codieren/Decodieren von Bytearrays in Base64 vermeiden lässt. Die App kann die benutzerdefinierte Serialisierung anwenden und die resultierenden Bytes übergeben. Weitere Informationen finden Sie unter Aufrufen von JavaScript-Funktionen über .NET-Methoden in Blazor in ASP.NET Core.
Blazor unterstützt das Rückgängigmachen von JS-Interop-Marshalling, wenn große Mengen an .NET-Objekten schnell serialisiert werden müssen oder wenn große oder viele .NET-Objekte serialisiert werden müssen. Weitere Informationen finden Sie unter Aufrufen von JavaScript-Funktionen über .NET-Methoden in Blazor in ASP.NET Core.
DOM-Bereinigungsvorgänge während der Beseitigung von Komponenten
Führen Sie nicht den JS-Interopcode für die DOM-Bereinigungsvorgänge während der Beseitigung von Komponenten aus. Verwenden Sie stattdessen aus folgenden Gründen auf dem Client das MutationObserver
-Muster in JavaScript (JS):
- Die Komponente wurde möglicherweise nach Ausführung des Bereinigungscodes in
Dispose{Async}
aus dem DOM entfernt. - Beim serverseitigen Rendering wurde der Blazor-Renderer möglicherweise bereits durch das Framework verworfen, wenn der Bereinigungscode in
Dispose{Async}
ausgeführt wird.
Mit dem Muster MutationObserver
können Sie eine Funktion ausführen, wenn ein Element aus dem DOM entfernt wird.
Im folgenden Beispiel gilt für die DOMCleanup
-Komponente:
- Sie enthält ein
<div>
-Element mitcleanupDiv
alsid
. Das<div>
-Element wird zusammen mit dem restlichen DOM-Markup der Komponente aus dem DOM entfernt, wenn die Komponente aus dem DOM entfernt wird. - Lädt die
DOMCleanup
-JS-Klasse aus der DateiDOMCleanup.razor.js
und ruft diecreateObserver
-Funktion auf, um denMutationObserver
-Rückruf einzurichten. Diese Aufgaben werden in derOnAfterRenderAsync
-Lebenszyklusmethode durchgeführt.
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)
{
await module.DisposeAsync();
}
}
}
Im folgenden Beispiel wird der MutationObserver
-Rückruf jedes Mal ausgeführt, wenn eine DOM-Änderung erfolgt. Führen Sie den Bereinigungscode aus, wenn die if
-Anweisung bestätigt, dass das Zielelement (cleanupDiv
) entfernt wurde (if (targetRemoved) { ... }
). Es ist wichtig, MutationObserver
zu trennen und zu löschen, um nach Ausführung des Bereinigungscodes einen Arbeitsspeicherverlust zu vermeiden.
DOMCleanup.razor.js
zusammen mit der DOMCleanup
-Komponente von weiter oben:
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;
JavaScript-Interopaufrufe ohne Verbindung
Dieser Abschnitt gilt nur für serverseitige Apps.
JavaScript-Interopaufrufe (JS) können nicht ausgegeben werden, nachdem eine SignalR-Verbindung getrennt wurde. Ohne eine Verbindung während der Komponentenbereinigung oder zu jedem anderen Zeitpunkt, an dem keine Verbindung vorhanden ist, schlagen die folgenden Methodenaufrufe fehl und protokollieren eine Meldung, dass die Verbindung als JSDisconnectedException getrennt wurde:
- JS-Interopmethodenaufrufe
Dispose
/DisposeAsync
ruft ein beliebiges IJSObjectReference-Element auf.
Um die Protokollierung von JSDisconnectedException zu vermeiden oder benutzerdefinierte Informationen zu protokollieren, fangen Sie die Ausnahme in einer try-catch
-Anweisung ab.
Für das folgende Beispiel für Komponbereinigung gilt:
- Die Komponente implementiert IAsyncDisposable.
objInstance
ist eine IJSObjectReference.- JSDisconnectedException wird abgefangen und nicht protokolliert.
- Optional können Sie benutzerdefinierte Informationen in der
catch
-Anweisung auf beliebiger Protokollebene protokollieren. Im folgenden Beispiel werden keine benutzerdefinierten Informationen protokolliert, da davon ausgegangen wird, dass es dem Entwickler gleichgültig ist, wann oder wo Verbindungen während der Komponentenbereinigung getrennt werden.
async ValueTask IAsyncDisposable.DisposeAsync()
{
try
{
if (objInstance is not null)
{
await objInstance.DisposeAsync();
}
}
catch (JSDisconnectedException)
{
}
}
Wenn Sie ihre eigenen JS-Objekte bereinigen oder anderen JS-Code auf dem Client ausführen müssen, nachdem eine Verbindung verloren gegangen ist, verwenden Sie das MutationObserver
-Muster in JS auf dem Client. Mit dem Muster MutationObserver
können Sie eine Funktion ausführen, wenn ein Element aus dem DOM entfernt wird.
Weitere Informationen finden Sie in den folgenden Artikeln:
- Behandeln von Fehlern in ASP.NET Core Blazor-Apps: Im Abschnitt JavaScript-Interop wird die Fehlerbehandlung in JS-Interopszenarien erläutert.
- ASP.NET Core Razor-Komponentenlebenszyklus: Im Abschnitt Komponentenbereinigung mit
IDisposable
undIAsyncDisposable
wird beschrieben, wie Bereinigungsmuster in Razor-Komponenten implementiert werden.
Zwischengespeicherte JavaScript-Dateien
JavaScript-Dateien (JS) und andere statische Objekte werden in der Regel während der Entwicklung in der Development
-Umgebung nicht auf Clients zwischengespeichert. Während der Entwicklung enthalten statische Ressourcenanforderungen den Cache-Control
-Header mit einem Wert von no-cache
oder max-age
mit einem Wert 0 (0
).
Während der Produktion in der Production
-Umgebung werden JS-Dateien in der Regel von Clients zwischengespeichert.
Um das clientseitige Zwischenspeichern in Browsern zu deaktivieren, verwenden Entwickler in der Regel einen der folgenden Ansätze:
- Deaktivieren Sie die Zwischenspeicherung, wenn die Entwicklertoolkonsole des Browsers geöffnet ist. Anleitungen finden Sie in der Dokumentation zur Entwicklertools der einzelnen Browser-Maintainer:
- Führen Sie eine manuelle Browseraktualisierung einer Webseite der App Blazor durch, um JS-Dateien erneut vom Server zu laden. Die HTTP-Middleware zur Zwischenspeicherung von ASP.NET Core verwendet immer einen gültigen
Cache-Control
-Header (kein Caching), der von einem Client gesendet wird.
Weitere Informationen finden Sie unter:
Größenbeschränkungen bei JavaScript-Interop-Aufrufen
Dieser Abschnitt gilt nur für interaktive Komponenten in serverseitigen Apps. Bei clientseitigen Komponenten erzwingt das Framework keine Einschränkungen hinsichtlich der Größe von JS-Interop-Eingaben und -Ausgaben.
Bei interaktiven Komponenten in serverseitigen Apps wird die Größe von JS-Interop-Aufrufen, die Daten vom Client an den Server übergeben, durch die maximale Größe eingehender SignalR-Nachrichten beschränkt, die für Hubmethoden zulässig sind. Dies wird durch HubOptions.MaximumReceiveMessageSize erzwungen (Standardwert: 32 KB). SignalR-Nachrichten von JS an .NET, die größer als MaximumReceiveMessageSize sich, lösen einen Fehler aus. Das Framework beinhaltet keine Beschränkungen hinsichtlich der Größe einer SignalR-Nachricht vom Hub an einen Client. Weitere Informationen zum Größenlimit sowie Fehlermeldungen und Anleitungen zum Umgang mit Nachrichtengrößenbeschränkungen finden Sie im ASP.NET Core-Blazor-SignalR-Leitfaden unter Maximale Größe für empfangene Nachrichten.
Ermitteln, wo die App ausgeführt wird
Wenn es für die App relevant ist, zu wissen, wo Code für JS-Interopaufrufe ausgeführt wird, verwenden Sie OperatingSystem.IsBrowser, um festzustellen, ob die Komponente im Kontext des Browsers in WebAssembly ausgeführt wird.