Aufrufen von .NET-Methoden von JavaScript-Funktionen in 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.
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.
In diesem Artikel wird erläutert, wie .NET-Methoden aus JavaScript (JS) aufgerufen werden.
Weitere Informationen zum Aufrufen von JS-Funktionen in .NET finden Sie unter Aufrufen von JavaScript-Funktionen über .NET-Methoden in Blazor in ASP.NET Core.
Aufrufen einer statischen .NET-Methode
Um eine statische .NET-Methode über JavaScript (JS) aufzurufen, verwenden Sie die JS-Funktionen:
DotNet.invokeMethodAsync
(empfohlen): Asynchron für serverseitige und clientseitige Komponenten.DotNet.invokeMethod
: Nur synchron für clientseitige Komponenten.
Übergeben Sie den Namen der Assembly, die die Methode enthält, den Bezeichner der statischen .NET-Methode und alle Argumente.
Im folgenden Beispiel:
- Der Platzhalter
{ASSEMBLY NAME}
ist der Assemblyname der App. - Der Platzhalter
{.NET METHOD ID}
ist der Bezeichner der .NET-Methode. - Der Platzhalter
{ARGUMENTS}
steht für optionale, durch Komma getrennte Argumente, die an die Methode übergeben werden sollen, von denen jedes JSON-serialisierbar sein muss.
DotNet.invokeMethodAsync('{ASSEMBLY NAME}', '{.NET METHOD ID}', {ARGUMENTS});
DotNet.invokeMethodAsync
gibt ein JS Promise
zurück, das das Ergebnis des Vorgangs darstellt. DotNet.invokeMethod
(clientseitige Komponenten) gibt das Ergebnis des Vorgangs zurück.
Wichtig
Für serverseitige Komponenten wird die asynchrone Funktion (invokeMethodAsync
) anstelle der synchronen Version (invokeMethod
) empfohlen.
Die .NET-Methode muss öffentlich und statisch sein sowie das [JSInvokable]
-Attribut aufweisen.
Im folgenden Beispiel:
- Der Platzhalter
{<T>}
gibt den Rückgabetyp an, der nur für Methoden erforderlich ist, die einen Wert zurückgeben. - Der Platzhalter
{.NET METHOD ID}
ist der Bezeichner der Methode.
@code {
[JSInvokable]
public static Task{<T>} {.NET METHOD ID}()
{
...
}
}
Hinweis
Das Aufrufen von offenen generischen Methoden wird nicht mit statischen .NET-Methoden, sondern mit Instanzmethoden unterstützt. Weitere Informationen finden Sie im Abschnitt Aufrufen generischer .NET-Klassenmethoden.
In der folgenden Komponente gibt die C#-Methode ReturnArrayAsync
ein int
-Array zurück. Das [JSInvokable]
-Attribut wird auf die Methode angewendet, sodass die Methode von JS aufgerufen werden kann.
CallDotnet1.razor
:
@page "/call-dotnet-1"
@implements IAsyncDisposable
@inject IJSRuntime JS
<PageTitle>Call .NET 1</PageTitle>
<h1>Call .NET Example 1</h1>
<p>
<button id="btn">Trigger .NET static method</button>
</p>
<p>
See the result in the developer tools console.
</p>
@code {
private IJSObjectReference? module;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
module = await JS.InvokeAsync<IJSObjectReference>("import",
"./Components/Pages/CallDotnet1.razor.js");
await module.InvokeVoidAsync("addHandlers");
}
}
[JSInvokable]
public static Task<int[]> ReturnArrayAsync() =>
Task.FromResult(new int[] { 11, 12, 13 });
async ValueTask IAsyncDisposable.DisposeAsync()
{
if (module is not null)
{
await module.DisposeAsync();
}
}
}
CallDotnet1.razor.js
:
export function returnArrayAsync() {
DotNet.invokeMethodAsync('BlazorSample', 'ReturnArrayAsync')
.then(data => {
console.log(data);
});
}
export function addHandlers() {
const btn = document.getElementById("btn");
btn.addEventListener("click", returnArrayAsync);
}
Die Funktion addHandlers
JS fügt der Schaltfläche ein click
-Ereignis hinzu. Die JS-Funktion returnArrayAsync
wird als Handler zugewiesen.
Die returnArrayAsync
JS-Funktion ruft die .NET-Methode ReturnArrayAsync
der Komponente auf und protokolliert das Ergebnis in der Webentwicklertools-Konsole des Browsers. BlazorSample
ist der Assemblyname der App.
CallDotnet1.razor
:
@page "/call-dotnet-1"
@implements IAsyncDisposable
@inject IJSRuntime JS
<PageTitle>Call .NET 1</PageTitle>
<h1>Call .NET Example 1</h1>
<p>
<button id="btn">Trigger .NET static method</button>
</p>
<p>
See the result in the developer tools console.
</p>
@code {
private IJSObjectReference? module;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
module = await JS.InvokeAsync<IJSObjectReference>("import",
"./Components/Pages/CallDotnet1.razor.js");
await module.InvokeVoidAsync("addHandlers");
}
}
[JSInvokable]
public static Task<int[]> ReturnArrayAsync() =>
Task.FromResult(new int[] { 11, 12, 13 });
async ValueTask IAsyncDisposable.DisposeAsync()
{
if (module is not null)
{
await module.DisposeAsync();
}
}
}
CallDotnet1.razor.js
:
export function returnArrayAsync() {
DotNet.invokeMethodAsync('BlazorSample', 'ReturnArrayAsync')
.then(data => {
console.log(data);
});
}
export function addHandlers() {
const btn = document.getElementById("btn");
btn.addEventListener("click", returnArrayAsync);
}
Die Funktion addHandlers
JS fügt der Schaltfläche ein click
-Ereignis hinzu. Die JS-Funktion returnArrayAsync
wird als Handler zugewiesen.
Die returnArrayAsync
JS-Funktion ruft die .NET-Methode ReturnArrayAsync
der Komponente auf und protokolliert das Ergebnis in der Webentwicklertools-Konsole des Browsers. BlazorSample
ist der Assemblyname der App.
CallDotNetExample1.razor
:
@page "/call-dotnet-example-1"
<h1>Call .NET Example 1</h1>
<p>
<button onclick="returnArrayAsync()">
Trigger .NET static method
</button>
</p>
@code {
[JSInvokable]
public static Task<int[]> ReturnArrayAsync()
{
return Task.FromResult(new int[] { 1, 2, 3 });
}
}
CallDotNetExample1.razor
:
@page "/call-dotnet-example-1"
<h1>Call .NET Example 1</h1>
<p>
<button onclick="returnArrayAsync()">
Trigger .NET static method
</button>
</p>
@code {
[JSInvokable]
public static Task<int[]> ReturnArrayAsync()
{
return Task.FromResult(new int[] { 1, 2, 3 });
}
}
CallDotNetExample1.razor
:
@page "/call-dotnet-example-1"
<h1>Call .NET Example 1</h1>
<p>
<button onclick="returnArrayAsync()">
Trigger .NET static method
</button>
</p>
@code {
[JSInvokable]
public static Task<int[]> ReturnArrayAsync()
{
return Task.FromResult(new int[] { 1, 2, 3 });
}
}
CallDotNetExample1.razor
:
@page "/call-dotnet-example-1"
<h1>Call .NET Example 1</h1>
<p>
<button onclick="returnArrayAsync()">
Trigger .NET static method
</button>
</p>
@code {
[JSInvokable]
public static Task<int[]> ReturnArrayAsync()
{
return Task.FromResult(new int[] { 1, 2, 3 });
}
}
Das HTML-Attribut onclick
des <button>
-Elements ist die Ereignishandlerzuweisung onclick
von JavaScript für die Verarbeitung von click
-Ereignissen, nicht das @onclick
-Direktivenattribut von Blazor. Die JS-Funktion returnArrayAsync
wird als Handler zugewiesen.
Die folgende returnArrayAsync
JS-Funktion ruft die .NET-Methode ReturnArrayAsync
der Komponente auf, die das Ergebnis in der Konsole der Webentwicklertools des Browsers protokolliert. BlazorSample
ist der Assemblyname der App.
<script>
window.returnArrayAsync = () => {
DotNet.invokeMethodAsync('BlazorSample', 'ReturnArrayAsync')
.then(data => {
console.log(data);
});
};
</script>
Hinweis
Allgemeine Anleitungen zu JS Standort und unseren Empfehlungen für Produktions-Apps finden Sie unter JavaScript-Speicherort in ASP.NET Core Blazor -Apps.
Bei Auswahl der Trigger .NET static method
-Schaltfläche werden die Arraydaten in der Konsolenausgabe der Entwicklertools des Browsers angezeigt. Das Format der Ausgabe unterscheidet sich von Browser zu Browser geringfügig. Die folgende Ausgabe veranschaulicht das Format von Microsoft Edge:
Array(3) [ 11, 12, 13 ]
Übergeben Sie Daten an eine .NET-Methode, wenn Sie die Funktion invokeMethodAsync
aufrufen, indem Sie die Daten als Argumente übergeben.
Um die Übergabe von Daten an .NET zu demonstrieren, übergeben Sie der ReturnArrayAsync
-Methode eine Startposition, wobei die Methode in JS aufgerufen wird:
export function returnArrayAsync() {
DotNet.invokeMethodAsync('BlazorSample', 'ReturnArrayAsync', 14)
.then(data => {
console.log(data);
});
}
<script>
window.returnArrayAsync = () => {
DotNet.invokeMethodAsync('BlazorSample', 'ReturnArrayAsync', 14)
.then(data => {
console.log(data);
});
};
</script>
Die aufrufbare ReturnArrayAsync
-Methode der Komponente erhält die Startposition und konstruiert daraus das Array. Das Array wird für die Protokollierung an die Konsole zurückgegeben:
[JSInvokable]
public static Task<int[]> ReturnArrayAsync(int startPosition) =>
Task.FromResult(Enumerable.Range(startPosition, 3).ToArray());
Nachdem die App neu kompiliert und der Browser aktualisiert wurde, wird die folgende Ausgabe in der Konsole des Browsers angezeigt, wenn die Schaltfläche ausgewählt wird:
Array(3) [ 14, 15, 16 ]
Der .NET-Methodenbezeichner für den JS-Aufruf ist der .NET-Methodenname, aber Sie können mit dem [JSInvokable]
-Attribut-Konstruktor einen anderen Bezeichner angeben. Im folgenden Beispiel ist DifferentMethodName
der zugewiesene Methodenbezeichner für die ReturnArrayAsync
-Methode:
[JSInvokable("DifferentMethodName")]
Rufen Sie im Aufruf von DotNet.invokeMethodAsync
(serverseitige oder clientseitige Komponenten) oder DotNet.invokeMethod
(nur clientseitige Komponenten) DifferentMethodName
auf, um die .NET-Methode ReturnArrayAsync
auszuführen:
DotNet.invokeMethodAsync('BlazorSample', 'DifferentMethodName');
DotNet.invokeMethod('BlazorSample', 'DifferentMethodName');
(nur clientseitige Komponenten)
Hinweis
Im Beispiel für die ReturnArrayAsync
-Methode in diesem Abschnitt wird das Ergebnis einer Taskohne Verwendung der expliziten C#-Schlüsselwörter async
und await
zurückgegeben. Das Codieren von Methoden mit async
und await
ist typisch für Methoden, die das Schlüsselwort await
verwenden, um den Wert asynchroner Vorgänge zurückzugeben.
ReturnArrayAsync
-Methode mit den Schlüsselwörtern async
und await
:
[JSInvokable]
public static async Task<int[]> ReturnArrayAsync() =>
await Task.FromResult(new int[] { 11, 12, 13 });
Weitere Informationen finden Sie unter Asynchrone Programmierung mit Async und Await in der C#-Anleitung.
Erstellen von Verweisen auf JavaScript-Objekte und -Daten für die Übergabe an .NET
Rufen Sie DotNet.createJSObjectReference(jsObject)
auf, um einen JS-Objektverweis zu erstellen, der an .NET übergeben werden kann, wobei jsObject
das JS Object
-Objekt ist, das zum Erstellen des JS-Objektverweises verwendet wird. Im folgenden Beispiel wird ein Verweis auf das nicht serialisierbare window
-Objekt an .NET übergeben, das es in der C#-Methode ReceiveWindowObject
als IJSObjectReference empfängt:
DotNet.invokeMethodAsync('{ASSEMBLY NAME}', 'ReceiveWindowObject',
DotNet.createJSObjectReference(window));
[JSInvokable]
public static void ReceiveWindowObject(IJSObjectReference objRef)
{
...
}
Im Beispiel oben steht der Platzhalter {ASSEMBLY NAME}
für den Namespace der App.
Hinweis
Das obige Beispiel erfordert kein Löschen von JSObjectReference
, da in JS kein Verweis auf das window
-Objekt gespeichert wird.
Die Beibehaltung eines Verweises auf einen JSObjectReference
erfordert die Löschung des Verweises, um einen JS-Arbeitsspeicherverlust auf dem Client zu vermeiden. Mit dem folgenden Beispiel wird der vorherige Code so umgestaltet, dass ein Verweis auf den JSObjectReference
erfasst wird. Danach erfolgt ein Aufruf von DotNet.disposeJSObjectReference()
, um den Verweis zu löschen:
var jsObjectReference = DotNet.createJSObjectReference(window);
DotNet.invokeMethodAsync('{ASSEMBLY NAME}', 'ReceiveWindowObject', jsObjectReference);
DotNet.disposeJSObjectReference(jsObjectReference);
Im Beispiel oben steht der Platzhalter {ASSEMBLY NAME}
für den Namespace der App.
Rufen Sie auf DotNet.createJSStreamReference(streamReference)
, um einen JS-Datenstromverweis zu erstellen, damit dieser an .NET übergeben werden kann, wobei streamReference
ein ArrayBuffer
, Blob
oder ein beliebiges typisiertes Array wie Uint8Array
oder Float32Array
zum Erstellen des JS-Datenstromverweises ist.
Aufrufen einer .NET-Instanzmethode
So rufen Sie eine .NET-Instanzmethode in JavaScript (JS) auf:
Übergeben Sie die .NET-Instanz als Verweis auf JS, indem Sie die Instanz in DotNetObjectReference einschließen und dafür Create aufrufen.
Rufen Sie eine .NET-Instanzmethode über JS mit
invokeMethodAsync
(empfohlen) oderinvokeMethod
(nur clientseitige Komponenten) aus dem übergebenen .NET-Objektverweis (DotNetObjectReference) auf. Übergeben Sie den Bezeichner der .NET-Instanzmethode und alle vorhandenen Argumente. Die .NET-Instanz kann auch als Argument übergeben werden, wenn andere .NET-Methoden von JS aus aufgerufen werden.Siehe folgendes Beispiel:
dotNetHelper
ist ein DotNetObjectReference.- Der Platzhalter
{.NET METHOD ID}
ist der Bezeichner der .NET-Methode. - Der Platzhalter
{ARGUMENTS}
steht für optionale, durch Komma getrennte Argumente, die an die Methode übergeben werden sollen, von denen jedes JSON-serialisierbar sein muss.
dotNetHelper.invokeMethodAsync('{.NET METHOD ID}', {ARGUMENTS});
Hinweis
invokeMethodAsync
undinvokeMethod
akzeptieren beim Aufrufen einer Instanzmethode keinen Assemblynamenparameter.invokeMethodAsync
gibt ein JSPromise
zurück, das das Ergebnis des Vorgangs darstellt.invokeMethod
(nur clientseitige Komponenten) gibt das Ergebnis des Vorgangs zurück.Wichtig
Für serverseitige Komponenten wird die asynchrone Funktion (
invokeMethodAsync
) anstelle der synchronen Version (invokeMethod
) empfohlen.Löschen Sie DotNetObjectReference.
In den folgenden Abschnitten dieses Artikels werden verschiedene Ansätze zum Aufrufen einer .NET-Instanzmethode veranschaulicht:
Umgehen der Kürzung von über JavaScript aufrufbaren .NET-Methoden
Dieser Abschnitt gilt für clientseitige Apps mit aktivierter Ahead-of-time-Kompilierung und erneuter Verknüpfung der Runtime.
Mehrere Beispiele in den folgenden Abschnitten basieren auf einem Klasseninstanzansatz, bei dem die mit dem [JSInvokable]
-Attribut gekennzeichnete und durch JavaScript aufrufbare .NET-Methode ein Member einer Klasse ist, bei der es sich nicht um eine Razor-Komponente handelt. Wenn sich solche .NET-Methoden in einer Razor-Komponente befinden, sind sie vor dem erneuten Verknüpfen der Runtime und dem Kürzen geschützt. Um die .NET-Methoden vor dem Kürzen außerhalb von Razor-Komponenten zu schützen, implementieren Sie die Methoden mit dem DynamicDependency
-Attribut für den Konstruktor der Klasse. Dies wird im folgenden Beispiel veranschaulicht:
using System.Diagnostics.CodeAnalysis;
using Microsoft.JSInterop;
public class ExampleClass {
[DynamicDependency(nameof(ExampleJSInvokableMethod))]
public ExampleClass()
{
}
[JSInvokable]
public string ExampleJSInvokableMethod()
{
...
}
}
Weitere Informationen finden Sie unter Vorbereiten von .NET-Bibliotheken für Kürzungen: DynamicDependency.
Übergeben von DotNetObjectReference
an eine einzelne JavaScript-Funktion
Im Beispiel in diesem Abschnitt wird veranschaulicht, wie ein DotNetObjectReferencean eine einzelne JavaScript-Funktion (JS) übergeben wird.
Die folgende sayHello1
JS-Funktion empfängt DotNetObjectReference und ruft invokeMethodAsync
auf, um die .NET-Methode GetHelloMessage
einer Komponente aufzurufen:
<script>
window.sayHello1 = (dotNetHelper) => {
return dotNetHelper.invokeMethodAsync('GetHelloMessage');
};
</script>
Hinweis
Allgemeine Anleitungen zum JSSpeicherort und zu unseren Empfehlungen für Produktions-Apps finden Sie unter JavaScript-Speicherort in ASP.NET CoreBlazor-Apps in ASP.NET Core.
Im vorherigen Beispiel ist der Variablenname dotNetHelper
willkürlich gewählt und kann in einen beliebigen Namen geändert werden.
Für die folgende -Komponente gilt:
- Die Komponente verfügt über eine .NET-Methode mit dem Namen
GetHelloMessage
, die von JS aufgerufen werden kann. - Bei Auswahl der Schaltfläche
Trigger .NET instance method
wird die JS-FunktionsayHello1
mit DotNetObjectReference aufgerufen. sayHello1
:- Ruft
GetHelloMessage
auf und empfängt die resultierende Nachricht. - Gibt die resultierende Nachricht an die aufrufende
TriggerDotNetInstanceMethod
-Methode zurück.
- Ruft
- Die von
sayHello1
inresult
zurückgegebene Nachricht wird dem Benutzer angezeigt. - Um einen Arbeitsspeicherverlust zu vermeiden und eine automatische Speicherbereinigung zu ermöglichen, wird der von DotNetObjectReference erstellte .NET-Objektverweis in der
Dispose
-Methode gelöscht.
CallDotnet2.razor
:
@page "/call-dotnet-2"
@implements IDisposable
@inject IJSRuntime JS
<PageTitle>Call .NET 2</PageTitle>
<h1>Call .NET Example 2</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
private DotNetObjectReference<CallDotnet2>? objRef;
protected override void OnInitialized() =>
objRef = DotNetObjectReference.Create(this);
public async Task TriggerDotNetInstanceMethod() =>
result = await JS.InvokeAsync<string>("sayHello1", objRef);
[JSInvokable]
public string GetHelloMessage() => $"Hello, {name}!";
public void Dispose() => objRef?.Dispose();
}
CallDotnet2.razor
:
@page "/call-dotnet-2"
@implements IDisposable
@inject IJSRuntime JS
<PageTitle>Call .NET 2</PageTitle>
<h1>Call .NET Example 2</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
private DotNetObjectReference<CallDotnet2>? objRef;
protected override void OnInitialized() =>
objRef = DotNetObjectReference.Create(this);
public async Task TriggerDotNetInstanceMethod() =>
result = await JS.InvokeAsync<string>("sayHello1", objRef);
[JSInvokable]
public string GetHelloMessage() => $"Hello, {name}!";
public void Dispose() => objRef?.Dispose();
}
CallDotNetExample2.razor
:
@page "/call-dotnet-example-2"
@implements IDisposable
@inject IJSRuntime JS
<h1>Call .NET Example 2</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
private DotNetObjectReference<CallDotNetExample2>? objRef;
protected override void OnInitialized()
{
objRef = DotNetObjectReference.Create(this);
}
public async Task TriggerDotNetInstanceMethod()
{
result = await JS.InvokeAsync<string>("sayHello1", objRef);
}
[JSInvokable]
public string GetHelloMessage() => $"Hello, {name}!";
public void Dispose()
{
objRef?.Dispose();
}
}
CallDotNetExample2.razor
:
@page "/call-dotnet-example-2"
@implements IDisposable
@inject IJSRuntime JS
<h1>Call .NET Example 2</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
private DotNetObjectReference<CallDotNetExample2>? objRef;
protected override void OnInitialized()
{
objRef = DotNetObjectReference.Create(this);
}
public async Task TriggerDotNetInstanceMethod()
{
result = await JS.InvokeAsync<string>("sayHello1", objRef);
}
[JSInvokable]
public string GetHelloMessage() => $"Hello, {name}!";
public void Dispose()
{
objRef?.Dispose();
}
}
CallDotNetExample2.razor
:
@page "/call-dotnet-example-2"
@implements IDisposable
@inject IJSRuntime JS
<h1>Call .NET Example 2</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string name;
private string result;
private DotNetObjectReference<CallDotNetExample2> objRef;
protected override void OnInitialized()
{
objRef = DotNetObjectReference.Create(this);
}
public async Task TriggerDotNetInstanceMethod()
{
result = await JS.InvokeAsync<string>("sayHello1", objRef);
}
[JSInvokable]
public string GetHelloMessage() => $"Hello, {name}!";
public void Dispose()
{
objRef?.Dispose();
}
}
CallDotNetExample2.razor
:
@page "/call-dotnet-example-2"
@implements IDisposable
@inject IJSRuntime JS
<h1>Call .NET Example 2</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string name;
private string result;
private DotNetObjectReference<CallDotNetExample2> objRef;
protected override void OnInitialized()
{
objRef = DotNetObjectReference.Create(this);
}
public async Task TriggerDotNetInstanceMethod()
{
result = await JS.InvokeAsync<string>("sayHello1", objRef);
}
[JSInvokable]
public string GetHelloMessage() => $"Hello, {name}!";
public void Dispose()
{
objRef?.Dispose();
}
}
Im vorherigen Beispiel ist der Variablenname dotNetHelper
willkürlich gewählt und kann in einen beliebigen Namen geändert werden.
Verwenden Sie den folgenden Leitfaden, um Argumente an eine Instanzmethode zu übergeben:
Fügen Sie Parameter zum .NET-Methodenaufruf hinzu. Im folgenden Beispiel wird ein Name an die Methode übergeben. Fügen Sie der Liste bei Bedarf weitere Parameter hinzu.
<script>
window.sayHello2 = (dotNetHelper, name) => {
return dotNetHelper.invokeMethodAsync('GetHelloMessage', name);
};
</script>
Im vorherigen Beispiel ist der Variablenname dotNetHelper
willkürlich gewählt und kann in einen beliebigen Namen geändert werden.
Übergeben Sie die Parameterliste an die .NET-Methode.
CallDotnet3.razor
:
@page "/call-dotnet-3"
@implements IDisposable
@inject IJSRuntime JS
<PageTitle>Call .NET 3</PageTitle>
<h1>Call .NET Example 3</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
private DotNetObjectReference<CallDotnet3>? objRef;
protected override void OnInitialized() =>
objRef = DotNetObjectReference.Create(this);
public async Task TriggerDotNetInstanceMethod() =>
result = await JS.InvokeAsync<string>("sayHello2", objRef, name);
[JSInvokable]
public string GetHelloMessage(string passedName) => $"Hello, {passedName}!";
public void Dispose() => objRef?.Dispose();
}
CallDotnet3.razor
:
@page "/call-dotnet-3"
@implements IDisposable
@inject IJSRuntime JS
<PageTitle>Call .NET 3</PageTitle>
<h1>Call .NET Example 3</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
private DotNetObjectReference<CallDotnet3>? objRef;
protected override void OnInitialized() =>
objRef = DotNetObjectReference.Create(this);
public async Task TriggerDotNetInstanceMethod() =>
result = await JS.InvokeAsync<string>("sayHello2", objRef, name);
[JSInvokable]
public string GetHelloMessage(string passedName) => $"Hello, {passedName}!";
public void Dispose() => objRef?.Dispose();
}
CallDotNetExample3.razor
:
@page "/call-dotnet-example-3"
@implements IDisposable
@inject IJSRuntime JS
<h1>Call .NET Example 3</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
private DotNetObjectReference<CallDotNetExample3>? objRef;
protected override void OnInitialized()
{
objRef = DotNetObjectReference.Create(this);
}
public async Task TriggerDotNetInstanceMethod()
{
result = await JS.InvokeAsync<string>("sayHello2", objRef, name);
}
[JSInvokable]
public string GetHelloMessage(string passedName) => $"Hello, {passedName}!";
public void Dispose()
{
objRef?.Dispose();
}
}
CallDotNetExample3.razor
:
@page "/call-dotnet-example-3"
@implements IDisposable
@inject IJSRuntime JS
<h1>Call .NET Example 3</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
private DotNetObjectReference<CallDotNetExample3>? objRef;
protected override void OnInitialized()
{
objRef = DotNetObjectReference.Create(this);
}
public async Task TriggerDotNetInstanceMethod()
{
result = await JS.InvokeAsync<string>("sayHello2", objRef, name);
}
[JSInvokable]
public string GetHelloMessage(string passedName) => $"Hello, {passedName}!";
public void Dispose()
{
objRef?.Dispose();
}
}
CallDotNetExample3.razor
:
@page "/call-dotnet-example-3"
@implements IDisposable
@inject IJSRuntime JS
<h1>Call .NET Example 3</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string name;
private string result;
private DotNetObjectReference<CallDotNetExample3> objRef;
protected override void OnInitialized()
{
objRef = DotNetObjectReference.Create(this);
}
public async Task TriggerDotNetInstanceMethod()
{
result = await JS.InvokeAsync<string>("sayHello2", objRef, name);
}
[JSInvokable]
public string GetHelloMessage(string passedName) => $"Hello, {passedName}!";
public void Dispose()
{
objRef?.Dispose();
}
}
CallDotNetExample3.razor
:
@page "/call-dotnet-example-3"
@implements IDisposable
@inject IJSRuntime JS
<h1>Call .NET Example 3</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string name;
private string result;
private DotNetObjectReference<CallDotNetExample3> objRef;
protected override void OnInitialized()
{
objRef = DotNetObjectReference.Create(this);
}
public async Task TriggerDotNetInstanceMethod()
{
result = await JS.InvokeAsync<string>("sayHello2", objRef, name);
}
[JSInvokable]
public string GetHelloMessage(string passedName) => $"Hello, {passedName}!";
public void Dispose()
{
objRef?.Dispose();
}
}
Im vorherigen Beispiel ist der Variablenname dotNetHelper
willkürlich gewählt und kann in einen beliebigen Namen geändert werden.
Übergeben von DotNetObjectReference
an eine Klasse mit mehreren JavaScript-Funktionen
Im Beispiel in diesem Abschnitt wird veranschaulicht, wie ein DotNetObjectReferencean eine JavaScript-Klasse (JS) mit mehreren Funktionen übergeben wird.
Erstellen und übergeben Sie einen DotNetObjectReference aus der OnAfterRenderAsync
-Lebenszyklusmethode an eine JS-Klasse, damit er von mehreren Funktionen verwendet werden kann. Stellen Sie sicher, dass der .NET-Code DotNetObjectReference wie im folgenden Beispiel gezeigt verwirft.
In der folgenden Komponente rufen die Trigger JS function
-Schaltflächen JS-Funktionen auf, indem sie die JSonclick
-Eigenschaft und nicht das @onclick
-Anweisungsattribut von Blazor festlegen.
CallDotNetExampleOneHelper.razor
:
@page "/call-dotnet-example-one-helper"
@implements IAsyncDisposable
@inject IJSRuntime JS
<PageTitle>Call .NET Example</PageTitle>
<h1>Pass <code>DotNetObjectReference</code> to a JavaScript class</h1>
<p>
<label>
Message: <input @bind="name" />
</label>
</p>
<p>
<button id="sayHelloBtn">
Trigger JS function <code>sayHello</code>
</button>
</p>
<p>
<button id="welcomeVisitorBtn">
Trigger JS function <code>welcomeVisitor</code>
</button>
</p>
@code {
private IJSObjectReference? module;
private string? name;
private DotNetObjectReference<CallDotNetExampleOneHelper>? dotNetHelper;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
module = await JS.InvokeAsync<IJSObjectReference>("import",
"./Components/Pages/CallDotNetExampleOneHelper.razor.js");
dotNetHelper = DotNetObjectReference.Create(this);
await module.InvokeVoidAsync("GreetingHelpers.setDotNetHelper",
dotNetHelper);
await module.InvokeVoidAsync("addHandlers");
}
}
[JSInvokable]
public string GetHelloMessage() => $"Hello, {name}!";
[JSInvokable]
public string GetWelcomeMessage() => $"Welcome, {name}!";
async ValueTask IAsyncDisposable.DisposeAsync()
{
if (module is not null)
{
await module.DisposeAsync();
}
dotNetHelper?.Dispose();
}
}
Im vorherigen Beispiel:
JS
ist eine eingefügte IJSRuntime-Instanz. IJSRuntime wird vom Blazor-Framework registriert.- Der Variablenname
dotNetHelper
ist willkürlich gewählt und kann in einen beliebigen Namen geändert werden. - Die Komponente muss DotNetObjectReference explizit verwerfen, um die Garbage Collection zuzulassen und einen Speicherverlust zu verhindern.
CallDotNetExampleOneHelper.razor.js
:
export class GreetingHelpers {
static dotNetHelper;
static setDotNetHelper(value) {
GreetingHelpers.dotNetHelper = value;
}
static async sayHello() {
const msg =
await GreetingHelpers.dotNetHelper.invokeMethodAsync('GetHelloMessage');
alert(`Message from .NET: "${msg}"`);
}
static async welcomeVisitor() {
const msg =
await GreetingHelpers.dotNetHelper.invokeMethodAsync('GetWelcomeMessage');
alert(`Message from .NET: "${msg}"`);
}
}
export function addHandlers() {
const sayHelloBtn = document.getElementById("sayHelloBtn");
sayHelloBtn.addEventListener("click", GreetingHelpers.sayHello);
const welcomeVisitorBtn = document.getElementById("welcomeVisitorBtn");
welcomeVisitorBtn.addEventListener("click", GreetingHelpers.welcomeVisitor);
}
Im vorherigen Beispiel ist der Variablenname dotNetHelper
willkürlich gewählt und kann in einen beliebigen Namen geändert werden.
@page "/call-dotnet-example-one-helper"
@implements IDisposable
@inject IJSRuntime JS
<h1>Pass <code>DotNetObjectReference</code> to a JavaScript class</h1>
<p>
<label>
Message: <input @bind="name" />
</label>
</p>
<p>
<button onclick="GreetingHelpers.sayHello()">
Trigger JS function <code>sayHello</code>
</button>
</p>
<p>
<button onclick="GreetingHelpers.welcomeVisitor()">
Trigger JS function <code>welcomeVisitor</code>
</button>
</p>
@code {
private string? name;
private DotNetObjectReference<CallDotNetExampleOneHelper>? dotNetHelper;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
dotNetHelper = DotNetObjectReference.Create(this);
await JS.InvokeVoidAsync("GreetingHelpers.setDotNetHelper",
dotNetHelper);
}
}
[JSInvokable]
public string GetHelloMessage() => $"Hello, {name}!";
[JSInvokable]
public string GetWelcomeMessage() => $"Welcome, {name}!";
public void Dispose()
{
dotNetHelper?.Dispose();
}
}
Im vorherigen Beispiel:
JS
ist eine eingefügte IJSRuntime-Instanz. IJSRuntime wird vom Blazor-Framework registriert.- Der Variablenname
dotNetHelper
ist willkürlich gewählt und kann in einen beliebigen Namen geändert werden. - Die Komponente muss DotNetObjectReference explizit verwerfen, um die Garbage Collection zuzulassen und einen Speicherverlust zu verhindern.
<script>
class GreetingHelpers {
static dotNetHelper;
static setDotNetHelper(value) {
GreetingHelpers.dotNetHelper = value;
}
static async sayHello() {
const msg =
await GreetingHelpers.dotNetHelper.invokeMethodAsync('GetHelloMessage');
alert(`Message from .NET: "${msg}"`);
}
static async welcomeVisitor() {
const msg =
await GreetingHelpers.dotNetHelper.invokeMethodAsync('GetWelcomeMessage');
alert(`Message from .NET: "${msg}"`);
}
}
window.GreetingHelpers = GreetingHelpers;
</script>
Im vorherigen Beispiel:
- Die
GreetingHelpers
-Klasse wird demwindow
-Objekt hinzugefügt, um die Klasse global zu definieren, wodurch Blazor sie für JS-Interop suchen kann. - Der Variablenname
dotNetHelper
ist willkürlich gewählt und kann in einen beliebigen Namen geändert werden.
Hinweis
Allgemeine Anleitungen zu JS Standort und unseren Empfehlungen für Produktions-Apps finden Sie unter JavaScript-Speicherort in ASP.NET Core Blazor -Apps.
Aufrufen generischer .NET-Klassenmethoden
JavaScript-Funktionen (JS) können generische .NET-Klassenmethoden aufrufen, wobei eine JS-Funktion eine .NET-Methode einer generischen Klasse aufruft.
In der folgenden generischen Typklasse (GenericType<TValue>
) gilt:
- Die Klasse verfügt über einen einzelnen Typparameter (
TValue
) mit einer einzelnen generischenValue
-Eigenschaft. - Die Klasse verfügt über zwei nicht generische Methoden, die mit dem
[JSInvokable]
-Attribut gekennzeichnet sind, jeweils mit einem generischen Typparameter namensnewValue
:Update
aktualisiert synchron den Wert vonValue
ausnewValue
.UpdateAsync
aktualisiert den Wert vonValue
ausnewValue
asynchron, nachdem ein awaitable-Task mit Task.Yield erstellt wurde, der asynchron an den aktuellen Kontext zurückgibt, wenn gewartet wird.
- Jede der Klassenmethoden schreibt den Typ von
TValue
und den Wert vonValue
in die Konsole. Das Schreiben in die Konsole dient nur zu Demonstrationszwecken. Produktions-Apps vermeiden in der Regel das Schreiben in die Konsole zugunsten von App-Protokollierung. Weitere Informationen finden Sie unter ASP.NET CoreBlazor-Protokollierung und Protokollierung in .NET Core und ASP.NET Core.
Hinweis
Offene generische Typen und Methoden geben keine Typen für Typplatzhalter an. Im Gegensatz dazu geben geschlossene Generics Typen für alle Typplatzhalter an. Die Beispiele in diesem Abschnitt veranschaulichen geschlossene Generics, aber das Aufrufen von JS-Interop--Instanzmethoden mit offenen Generics wird unterstützt. Die Verwendung von Open Generics wird nicht für statische .NET-Methodenaufrufe unterstützt, die weiter oben in diesem Artikel beschrieben wurden.
Weitere Informationen finden Sie in den folgenden Artikeln:
- Generische Klassen und Methoden (C#-Dokumentation)
- Generische Klassen (C#-Programmierhandbuch)
- Generics in .NET (.NET-Dokumentation)
GenericType.cs
:
using Microsoft.JSInterop;
public class GenericType<TValue>
{
public TValue? Value { get; set; }
[JSInvokable]
public void Update(TValue newValue)
{
Value = newValue;
Console.WriteLine($"Update: GenericType<{typeof(TValue)}>: {Value}");
}
[JSInvokable]
public async void UpdateAsync(TValue newValue)
{
await Task.Yield();
Value = newValue;
Console.WriteLine($"UpdateAsync: GenericType<{typeof(TValue)}>: {Value}");
}
}
Für die folgende invokeMethodsAsync
-Funktion gilt Folgendes:
- Die Methoden
Update
undUpdateAsync
der generischen Typklasse werden mit Argumenten aufgerufen, die Zeichenfolgen und Zahlen darstellen. - Clientseitige Apps unterstützen das synchrone Aufrufen von .NET-Methoden mit
invokeMethod
.syncInterop
empfängt einen booleschen Wert, der angibt, ob der Client über JS-Interoperabilität verfügt. WennsyncInterop
true
ist, wirdinvokeMethod
sicher aufgerufen. HatsyncInterop
den Wertfalse
, wird nur die asynchrone FunktioninvokeMethodAsync
aufgerufen, da die JS-Interoperabilität in einer serverseitigen Komponente ausgeführt wird. - Zu Demonstrationszwecken werden der DotNetObjectReference-Funktionsaufruf (
invokeMethod
oderinvokeMethodAsync
), die aufgerufene .NET-Methode (Update
oderUpdateAsync
) und das Argument in die Konsole geschrieben. Die Argumente verwenden eine Zufallszahl, um den Abgleich des JS-Funktionsaufrufs mit dem .NET-Methodenaufruf zu ermöglichen (auf der .NET-Seite auch in die Konsole geschrieben). Produktionscode schreibt in der Regel weder auf dem Client noch auf dem Server in die Konsole. Produktions-Apps verwenden in der Regel App-Protokollierung. Weitere Informationen finden Sie unter ASP.NET CoreBlazor-Protokollierung und Protokollierung in .NET Core und ASP.NET Core.
<script>
const randomInt = () => Math.floor(Math.random() * 99999);
window.invokeMethodsAsync = async (syncInterop, dotNetHelper1, dotNetHelper2) => {
var n = randomInt();
console.log(`JS: invokeMethodAsync:Update('string ${n}')`);
await dotNetHelper1.invokeMethodAsync('Update', `string ${n}`);
n = randomInt();
console.log(`JS: invokeMethodAsync:UpdateAsync('string ${n}')`);
await dotNetHelper1.invokeMethodAsync('UpdateAsync', `string ${n}`);
if (syncInterop) {
n = randomInt();
console.log(`JS: invokeMethod:Update('string ${n}')`);
dotNetHelper1.invokeMethod('Update', `string ${n}`);
}
n = randomInt();
console.log(`JS: invokeMethodAsync:Update(${n})`);
await dotNetHelper2.invokeMethodAsync('Update', n);
n = randomInt();
console.log(`JS: invokeMethodAsync:UpdateAsync(${n})`);
await dotNetHelper2.invokeMethodAsync('UpdateAsync', n);
if (syncInterop) {
n = randomInt();
console.log(`JS: invokeMethod:Update(${n})`);
dotNetHelper2.invokeMethod('Update', n);
}
};
</script>
Hinweis
Allgemeine Anleitungen zum JSSpeicherort und zu unseren Empfehlungen für Produktions-Apps finden Sie unter JavaScript-Speicherort in ASP.NET CoreBlazor-Apps in ASP.NET Core.
In der folgenden GenericsExample
-Komponente:
- Bei Auswahl der Schaltfläche
Invoke Interop
wird die JS-FunktioninvokeMethodsAsync
aufgerufen. - Ein Paar von DotNetObjectReference-Typen wird erstellt und an die JS-Funktion für Instanzen von
GenericType
alsstring
undint
übergeben.
GenericsExample.razor
:
@page "/generics-example"
@implements IDisposable
@inject IJSRuntime JS
<p>
<button @onclick="InvokeInterop">Invoke Interop</button>
</p>
<ul>
<li>genericType1: @genericType1?.Value</li>
<li>genericType2: @genericType2?.Value</li>
</ul>
@code {
private GenericType<string> genericType1 = new() { Value = "string 0" };
private GenericType<int> genericType2 = new() { Value = 0 };
private DotNetObjectReference<GenericType<string>>? objRef1;
private DotNetObjectReference<GenericType<int>>? objRef2;
protected override void OnInitialized()
{
objRef1 = DotNetObjectReference.Create(genericType1);
objRef2 = DotNetObjectReference.Create(genericType2);
}
public async Task InvokeInterop()
{
var syncInterop = OperatingSystem.IsBrowser();
await JS.InvokeVoidAsync(
"invokeMethodsAsync", syncInterop, objRef1, objRef2);
}
public void Dispose()
{
objRef1?.Dispose();
objRef2?.Dispose();
}
}
@page "/generics-example"
@implements IDisposable
@inject IJSRuntime JS
<p>
<button @onclick="InvokeInterop">Invoke Interop</button>
</p>
<ul>
<li>genericType1: @genericType1?.Value</li>
<li>genericType2: @genericType2?.Value</li>
</ul>
@code {
private GenericType<string> genericType1 = new() { Value = "string 0" };
private GenericType<int> genericType2 = new() { Value = 0 };
private DotNetObjectReference<GenericType<string>>? objRef1;
private DotNetObjectReference<GenericType<int>>? objRef2;
protected override void OnInitialized()
{
objRef1 = DotNetObjectReference.Create(genericType1);
objRef2 = DotNetObjectReference.Create(genericType2);
}
public async Task InvokeInterop()
{
var syncInterop = OperatingSystem.IsBrowser();
await JS.InvokeVoidAsync(
"invokeMethodsAsync", syncInterop, objRef1, objRef2);
}
public void Dispose()
{
objRef1?.Dispose();
objRef2?.Dispose();
}
}
Im vorangehenden Beispiel ist JS
eine injizierte IJSRuntime Instanz. IJSRuntime wird vom Blazor-Framework registriert.
Im Folgenden wird die typische Ausgabe des vorherigen Beispiels veranschaulicht, wenn die Schaltfläche Invoke Interop
in einer clientseitigen Komponente ausgewählt wird:
JS: invokeMethodAsync:Update('string 37802')
.NET: Update: GenericType<System.String>: string 37802
JS: invokeMethodAsync:UpdateAsync('string 53051')
JS: invokeMethod:Update('string 26784')
.NET: Update: GenericType<System.String>: string 26784
JS: invokeMethodAsync:Update(14107)
.NET: Update: GenericType<System.Int32>: 14107
JS: invokeMethodAsync:UpdateAsync(48995)
JS: invokeMethod:Update(12872)
.NET: Update: GenericType<System.Int32>: 12872
.NET: UpdateAsync: GenericType<System.String>: string 53051
.NET: UpdateAsync: GenericType<System.Int32>: 48995
Wenn das vorherige Beispiel in einer serverseitigen Komponente implementiert wird, werden die synchronen Aufrufe mit invokeMethod
vermieden. Für serverseitige Komponenten wird die asynchrone Funktion (invokeMethodAsync
) anstelle der synchronen Version (invokeMethod
) empfohlen.
Typische Ausgabe einer serverseitigen Komponente:
JS: invokeMethodAsync:Update('string 34809')
.NET: Update: GenericType<System.String>: string 34809
JS: invokeMethodAsync:UpdateAsync('string 93059')
JS: invokeMethodAsync:Update(41997)
.NET: Update: GenericType<System.Int32>: 41997
JS: invokeMethodAsync:UpdateAsync(24652)
.NET: UpdateAsync: GenericType<System.String>: string 93059
.NET: UpdateAsync: GenericType<System.Int32>: 24652
Die Ausgabebeispiele oben veranschaulichen, dass asynchrone Methoden in einer beliebigen Reihenfolge ausgeführt und abgeschlossen werden, abhängig von mehreren Faktoren, einschließlich Threadplanung und der Geschwindigkeit der Methodenausführung. Es ist nicht möglich, die Reihenfolge des Abschlusses für asynchrone Methodenaufrufe zuverlässig vorherzusagen.
Beispiele für Klasseninstanzen
Die folgende JS-Funktion sayHello1
:
- Ruft die .NET-Methode
GetHelloMessage
für das übergebene DotNetObjectReference auf. - Gibt die Nachricht von
GetHelloMessage
an densayHello1
-Aufrufer zurück.
<script>
window.sayHello1 = (dotNetHelper) => {
return dotNetHelper.invokeMethodAsync('GetHelloMessage');
};
</script>
Hinweis
Allgemeine Anleitungen zum JSSpeicherort und zu unseren Empfehlungen für Produktions-Apps finden Sie unter JavaScript-Speicherort in ASP.NET CoreBlazor-Apps in ASP.NET Core.
Im vorherigen Beispiel ist der Variablenname dotNetHelper
willkürlich gewählt und kann in einen beliebigen Namen geändert werden.
Die folgende HelloHelper
-Klasse verfügt über eine .NET-Methode mit dem Namen GetHelloMessage
, die von JS aufgerufen werden kann. Wenn HelloHelper
erstellt wird, wird der Name in der Name
-Eigenschaft verwendet, um eine Nachricht von GetHelloMessage
zurückzugeben.
HelloHelper.cs
:
using Microsoft.JSInterop;
namespace BlazorSample;
public class HelloHelper(string? name)
{
public string? Name { get; set; } = name ?? "No Name";
[JSInvokable]
public string GetHelloMessage() => $"Hello, {Name}!";
}
using Microsoft.JSInterop;
namespace BlazorSample;
public class HelloHelper(string? name)
{
public string? Name { get; set; } = name ?? "No Name";
[JSInvokable]
public string GetHelloMessage() => $"Hello, {Name}!";
}
using Microsoft.JSInterop;
public class HelloHelper
{
public HelloHelper(string? name)
{
Name = name ?? "No Name";
}
public string? Name { get; set; }
[JSInvokable]
public string GetHelloMessage() => $"Hello, {Name}!";
}
using Microsoft.JSInterop;
public class HelloHelper
{
public HelloHelper(string? name)
{
Name = name ?? "No Name";
}
public string? Name { get; set; }
[JSInvokable]
public string GetHelloMessage() => $"Hello, {Name}!";
}
using Microsoft.JSInterop;
public class HelloHelper
{
public HelloHelper(string name)
{
Name = name;
}
public string Name { get; set; }
[JSInvokable]
public string GetHelloMessage() => $"Hello, {Name}!";
}
using Microsoft.JSInterop;
public class HelloHelper
{
public HelloHelper(string name)
{
Name = name;
}
public string Name { get; set; }
[JSInvokable]
public string GetHelloMessage() => $"Hello, {Name}!";
}
Die CallHelloHelperGetHelloMessage
-Methode in der folgenden JsInteropClasses3
-Klasse ruft die JS-Funktion sayHello1
mit einer neuen Instanz von HelloHelper
auf.
JsInteropClasses3.cs
:
using Microsoft.JSInterop;
namespace BlazorSample;
public class JsInteropClasses3(IJSRuntime js)
{
private readonly IJSRuntime js = js;
public async ValueTask<string> CallHelloHelperGetHelloMessage(string? name)
{
using var objRef = DotNetObjectReference.Create(new HelloHelper(name));
return await js.InvokeAsync<string>("sayHello1", objRef);
}
}
using Microsoft.JSInterop;
namespace BlazorSample;
public class JsInteropClasses3(IJSRuntime js)
{
private readonly IJSRuntime js = js;
public async ValueTask<string> CallHelloHelperGetHelloMessage(string? name)
{
using var objRef = DotNetObjectReference.Create(new HelloHelper(name));
return await js.InvokeAsync<string>("sayHello1", objRef);
}
}
using Microsoft.JSInterop;
public class JsInteropClasses3
{
private readonly IJSRuntime js;
public JsInteropClasses3(IJSRuntime js)
{
this.js = js;
}
public async ValueTask<string> CallHelloHelperGetHelloMessage(string? name)
{
using var objRef = DotNetObjectReference.Create(new HelloHelper(name));
return await js.InvokeAsync<string>("sayHello1", objRef);
}
}
using Microsoft.JSInterop;
public class JsInteropClasses3
{
private readonly IJSRuntime js;
public JsInteropClasses3(IJSRuntime js)
{
this.js = js;
}
public async ValueTask<string> CallHelloHelperGetHelloMessage(string? name)
{
using var objRef = DotNetObjectReference.Create(new HelloHelper(name));
return await js.InvokeAsync<string>("sayHello1", objRef);
}
}
using System.Threading.Tasks;
using Microsoft.JSInterop;
public class JsInteropClasses3
{
private readonly IJSRuntime js;
public JsInteropClasses3(IJSRuntime js)
{
this.js = js;
}
public async ValueTask<string> CallHelloHelperGetHelloMessage(string name)
{
using var objRef = DotNetObjectReference.Create(new HelloHelper(name));
return await js.InvokeAsync<string>("sayHello1", objRef);
}
}
using System.Threading.Tasks;
using Microsoft.JSInterop;
public class JsInteropClasses3
{
private readonly IJSRuntime js;
public JsInteropClasses3(IJSRuntime js)
{
this.js = js;
}
public async ValueTask<string> CallHelloHelperGetHelloMessage(string name)
{
using var objRef = DotNetObjectReference.Create(new HelloHelper(name));
return await js.InvokeAsync<string>("sayHello1", objRef);
}
}
Um einen Arbeitsspeicherverlust zu vermeiden und die Garbage Collection zuzulassen, wird der von DotNetObjectReference erstellte .NET-Objektverweis gelöscht, wenn der Objektverweis nicht mit der using var
-Syntax übereinstimmt.
Bei Auswahl der Schaltfläche Trigger .NET instance method
in der folgenden Komponente, wird JsInteropClasses3.CallHelloHelperGetHelloMessage
mit dem Wert von name
aufgerufen.
CallDotnet4.razor
:
@page "/call-dotnet-4"
@inject IJSRuntime JS
<PageTitle>Call .NET 4</PageTitle>
<h1>Call .NET Example 4</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
private JsInteropClasses3? jsInteropClasses;
protected override void OnInitialized() =>
jsInteropClasses = new JsInteropClasses3(JS);
private async Task TriggerDotNetInstanceMethod()
{
if (jsInteropClasses is not null)
{
result = await jsInteropClasses.CallHelloHelperGetHelloMessage(name);
}
}
}
CallDotnet4.razor
:
@page "/call-dotnet-4"
@inject IJSRuntime JS
<PageTitle>Call .NET 4</PageTitle>
<h1>Call .NET Example 4</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
private JsInteropClasses3? jsInteropClasses;
protected override void OnInitialized() =>
jsInteropClasses = new JsInteropClasses3(JS);
private async Task TriggerDotNetInstanceMethod()
{
if (jsInteropClasses is not null)
{
result = await jsInteropClasses.CallHelloHelperGetHelloMessage(name);
}
}
}
CallDotNetExample4.razor
:
@page "/call-dotnet-example-4"
@inject IJSRuntime JS
<h1>Call .NET Example 4</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
private JsInteropClasses3? jsInteropClasses;
protected override void OnInitialized()
{
jsInteropClasses = new JsInteropClasses3(JS);
}
private async Task TriggerDotNetInstanceMethod()
{
if (jsInteropClasses is not null)
{
result = await jsInteropClasses.CallHelloHelperGetHelloMessage(name);
}
}
}
CallDotNetExample4.razor
:
@page "/call-dotnet-example-4"
@inject IJSRuntime JS
<h1>Call .NET Example 4</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
private JsInteropClasses3? jsInteropClasses;
protected override void OnInitialized()
{
jsInteropClasses = new JsInteropClasses3(JS);
}
private async Task TriggerDotNetInstanceMethod()
{
if (jsInteropClasses is not null)
{
result = await jsInteropClasses.CallHelloHelperGetHelloMessage(name);
}
}
}
CallDotNetExample4.razor
:
@page "/call-dotnet-example-4"
@inject IJSRuntime JS
<h1>Call .NET Example 4</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string name;
private string result;
private JsInteropClasses3 jsInteropClasses;
protected override void OnInitialized()
{
jsInteropClasses = new JsInteropClasses3(JS);
}
private async Task TriggerDotNetInstanceMethod()
{
result = await jsInteropClasses.CallHelloHelperGetHelloMessage(name);
}
}
CallDotNetExample4.razor
:
@page "/call-dotnet-example-4"
@inject IJSRuntime JS
<h1>Call .NET Example 4</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string name;
private string result;
private JsInteropClasses3 jsInteropClasses;
protected override void OnInitialized()
{
jsInteropClasses = new JsInteropClasses3(JS);
}
private async Task TriggerDotNetInstanceMethod()
{
result = await jsInteropClasses.CallHelloHelperGetHelloMessage(name);
}
}
Die folgende Abbildung zeigt die gerenderte Komponente mit dem Namen Amy Pond
im Name
-Feld. Nach Auswahl der Schaltfläche wird Hello, Amy Pond!
auf der Benutzeroberfläche angezeigt:
Das obige Muster, das in der Klasse JsInteropClasses3
veranschaulicht wird, kann auch vollständig in einer Komponente implementiert werden.
CallDotnet5.razor
:
@page "/call-dotnet-5"
@inject IJSRuntime JS
<PageTitle>Call .NET 5</PageTitle>
<h1>Call .NET Example 5</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
public async Task TriggerDotNetInstanceMethod()
{
using var objRef = DotNetObjectReference.Create(new HelloHelper(name));
result = await JS.InvokeAsync<string>("sayHello1", objRef);
}
}
CallDotnet5.razor
:
@page "/call-dotnet-5"
@inject IJSRuntime JS
<PageTitle>Call .NET 5</PageTitle>
<h1>Call .NET Example 5</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
public async Task TriggerDotNetInstanceMethod()
{
using var objRef = DotNetObjectReference.Create(new HelloHelper(name));
result = await JS.InvokeAsync<string>("sayHello1", objRef);
}
}
CallDotNetExample5.razor
:
@page "/call-dotnet-example-5"
@inject IJSRuntime JS
<h1>Call .NET Example 5</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
public async Task TriggerDotNetInstanceMethod()
{
using var objRef = DotNetObjectReference.Create(new HelloHelper(name));
result = await JS.InvokeAsync<string>("sayHello1", objRef);
}
}
CallDotNetExample5.razor
:
@page "/call-dotnet-example-5"
@inject IJSRuntime JS
<h1>Call .NET Example 5</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
public async Task TriggerDotNetInstanceMethod()
{
using var objRef = DotNetObjectReference.Create(new HelloHelper(name));
result = await JS.InvokeAsync<string>("sayHello1", objRef);
}
}
CallDotNetExample5.razor
:
@page "/call-dotnet-example-5"
@inject IJSRuntime JS
<h1>Call .NET Example 5</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string name;
private string result;
public async Task TriggerDotNetInstanceMethod()
{
using var objRef = DotNetObjectReference.Create(new HelloHelper(name));
result = await JS.InvokeAsync<string>("sayHello1", objRef);
}
}
CallDotNetExample5.razor
:
@page "/call-dotnet-example-5"
@inject IJSRuntime JS
<h1>Call .NET Example 5</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string name;
private string result;
public async Task TriggerDotNetInstanceMethod()
{
using var objRef = DotNetObjectReference.Create(new HelloHelper(name));
result = await JS.InvokeAsync<string>("sayHello1", objRef);
}
}
Um einen Arbeitsspeicherverlust zu vermeiden und die Garbage Collection zuzulassen, wird der von DotNetObjectReference erstellte .NET-Objektverweis gelöscht, wenn der Objektverweis nicht mit der using var
-Syntax übereinstimmt.
Die von der Komponente angezeigte Ausgabe lautet Hello, Amy Pond!
, wenn der Name Amy Pond
im Feld name
angegeben wird.
In der obigen -Komponente wird der .NET-Objektverweis gelöscht. Wenn eine Klasse oder Komponente DotNetObjectReference nicht löscht, muss es vom Client gelöscht werden, indem dispose
für das übergebene DotNetObjectReference aufgerufen wird:
window.{JS FUNCTION NAME} = (dotNetHelper) => {
dotNetHelper.invokeMethodAsync('{.NET METHOD ID}');
dotNetHelper.dispose();
}
Im vorherigen Beispiel:
- Der Platzhalter
{JS FUNCTION NAME}
ist der Name für die JS-Funktion. - Der Variablenname
dotNetHelper
ist willkürlich gewählt und kann in einen beliebigen Namen geändert werden. - Der Platzhalter
{.NET METHOD ID}
ist der Bezeichner der .NET-Methode.
Hilfsklasse für die .NET-Instanzmethode einer Komponente
Eine Hilfsklasse kann eine .NET-Instanzmethode als Action aufrufen. Hilfsklassen sind in Szenarien hilfreich, in denen statische .NET-Methoden nicht anwendbar sind:
- Auf einer Seite werden mehrere Komponenten desselben Typs gerendert.
- In serverseitigen Apps, in denen mehrere Benutzer*innen gleichzeitig die gleiche Komponente verwenden.
Im folgenden Beispiel:
- Die Komponente enthält mehrere
ListItem1
Komponenten. - Alle
ListItem1
-Komponenten bestehen aus einer Nachricht und einer Schaltfläche. - Wenn auf die Schaltfläche einer
ListItem1
-Komponente geklickt wird, ändert dieUpdateMessage
-Methode desListItem1
-Elements den Text des Listenelements und blendet die Schaltfläche aus.
Die folgende MessageUpdateInvokeHelper
-Klasse umfasst eine.NET-Methode UpdateMessageCaller
, die von JS aufgerufen werden kann, um die Action aufzurufen, die beim Instanziieren der Klasse angegeben wurde.
MessageUpdateInvokeHelper.cs
:
using Microsoft.JSInterop;
namespace BlazorSample;
public class MessageUpdateInvokeHelper(Action action)
{
private readonly Action action = action;
[JSInvokable]
public void UpdateMessageCaller() => action.Invoke();
}
using Microsoft.JSInterop;
namespace BlazorSample;
public class MessageUpdateInvokeHelper(Action action)
{
private readonly Action action = action;
[JSInvokable]
public void UpdateMessageCaller() => action.Invoke();
}
using Microsoft.JSInterop;
public class MessageUpdateInvokeHelper
{
private Action action;
public MessageUpdateInvokeHelper(Action action)
{
this.action = action;
}
[JSInvokable]
public void UpdateMessageCaller()
{
action.Invoke();
}
}
using Microsoft.JSInterop;
public class MessageUpdateInvokeHelper
{
private Action action;
public MessageUpdateInvokeHelper(Action action)
{
this.action = action;
}
[JSInvokable]
public void UpdateMessageCaller()
{
action.Invoke();
}
}
using System;
using Microsoft.JSInterop;
public class MessageUpdateInvokeHelper
{
private Action action;
public MessageUpdateInvokeHelper(Action action)
{
this.action = action;
}
[JSInvokable]
public void UpdateMessageCaller()
{
action.Invoke();
}
}
using System;
using Microsoft.JSInterop;
public class MessageUpdateInvokeHelper
{
private Action action;
public MessageUpdateInvokeHelper(Action action)
{
this.action = action;
}
[JSInvokable]
public void UpdateMessageCaller()
{
action.Invoke();
}
}
Die folgende JS-Funktion updateMessageCaller
ruft die .NET-Methode UpdateMessageCaller
auf.
<script>
window.updateMessageCaller = (dotNetHelper) => {
dotNetHelper.invokeMethodAsync('UpdateMessageCaller');
dotNetHelper.dispose();
}
</script>
Hinweis
Allgemeine Anleitungen zum JSSpeicherort und zu unseren Empfehlungen für Produktions-Apps finden Sie unter JavaScript-Speicherort in ASP.NET CoreBlazor-Apps in ASP.NET Core.
Im vorherigen Beispiel ist der Variablenname dotNetHelper
willkürlich gewählt und kann in einen beliebigen Namen geändert werden.
Die folgende ListItem1
-Komponente ist eine freigegebene Komponente, die in einer übergeordneten Komponente mehrmals verwendet werden kann und Listenelemente (<li>...</li>
) für eine HTML-Liste (<ul>...</ul>
oder <ol>...</ol>
) erstellt. Jede ListItem1
-Komponenteninstanz richtet eine Instanz von MessageUpdateInvokeHelper
ein, wobei eine Action auf die zugehörige UpdateMessage
-Methode festgelegt ist.
Bei Auswahl der Schaltfläche InteropCall
einer ListItem1
-Komponente wird updateMessageCaller
mit einem erstellten DotNetObjectReference für die MessageUpdateInvokeHelper
-Instanz aufgerufen. Dadurch kann das Framework UpdateMessageCaller
für die MessageUpdateInvokeHelper
-Instanz für das betreffende ListItem1
aufrufen. Das übergebene DotNetObjectReference wird in JS (dotNetHelper.dispose()
) gelöscht.
ListItem1.razor
:
@inject IJSRuntime JS
<li>
@message
<button @onclick="InteropCall" style="display:@display">InteropCall</button>
</li>
@code {
private string message = "Select one of these list item buttons.";
private string display = "inline-block";
private MessageUpdateInvokeHelper? messageUpdateInvokeHelper;
protected override void OnInitialized()
{
messageUpdateInvokeHelper = new MessageUpdateInvokeHelper(UpdateMessage);
}
protected async Task InteropCall()
{
if (messageUpdateInvokeHelper is not null)
{
await JS.InvokeVoidAsync("updateMessageCaller",
DotNetObjectReference.Create(messageUpdateInvokeHelper));
}
}
private void UpdateMessage()
{
message = "UpdateMessage Called!";
display = "none";
StateHasChanged();
}
}
@inject IJSRuntime JS
<li>
@message
<button @onclick="InteropCall" style="display:@display">InteropCall</button>
</li>
@code {
private string message = "Select one of these list item buttons.";
private string display = "inline-block";
private MessageUpdateInvokeHelper? messageUpdateInvokeHelper;
protected override void OnInitialized()
{
messageUpdateInvokeHelper = new MessageUpdateInvokeHelper(UpdateMessage);
}
protected async Task InteropCall()
{
if (messageUpdateInvokeHelper is not null)
{
await JS.InvokeVoidAsync("updateMessageCaller",
DotNetObjectReference.Create(messageUpdateInvokeHelper));
}
}
private void UpdateMessage()
{
message = "UpdateMessage Called!";
display = "none";
StateHasChanged();
}
}
@inject IJSRuntime JS
<li>
@message
<button @onclick="InteropCall" style="display:@display">InteropCall</button>
</li>
@code {
private string message = "Select one of these list item buttons.";
private string display = "inline-block";
private MessageUpdateInvokeHelper? messageUpdateInvokeHelper;
protected override void OnInitialized()
{
messageUpdateInvokeHelper = new MessageUpdateInvokeHelper(UpdateMessage);
}
protected async Task InteropCall()
{
if (messageUpdateInvokeHelper is not null)
{
await JS.InvokeVoidAsync("updateMessageCaller",
DotNetObjectReference.Create(messageUpdateInvokeHelper));
}
}
private void UpdateMessage()
{
message = "UpdateMessage Called!";
display = "none";
StateHasChanged();
}
}
@inject IJSRuntime JS
<li>
@message
<button @onclick="InteropCall" style="display:@display">InteropCall</button>
</li>
@code {
private string message = "Select one of these list item buttons.";
private string display = "inline-block";
private MessageUpdateInvokeHelper? messageUpdateInvokeHelper;
protected override void OnInitialized()
{
messageUpdateInvokeHelper = new MessageUpdateInvokeHelper(UpdateMessage);
}
protected async Task InteropCall()
{
if (messageUpdateInvokeHelper is not null)
{
await JS.InvokeVoidAsync("updateMessageCaller",
DotNetObjectReference.Create(messageUpdateInvokeHelper));
}
}
private void UpdateMessage()
{
message = "UpdateMessage Called!";
display = "none";
StateHasChanged();
}
}
@inject IJSRuntime JS
<li>
@message
<button @onclick="InteropCall" style="display:@display">InteropCall</button>
</li>
@code {
private string message = "Select one of these list item buttons.";
private string display = "inline-block";
private MessageUpdateInvokeHelper messageUpdateInvokeHelper;
protected override void OnInitialized()
{
messageUpdateInvokeHelper = new MessageUpdateInvokeHelper(UpdateMessage);
}
protected async Task InteropCall()
{
await JS.InvokeVoidAsync("updateMessageCaller",
DotNetObjectReference.Create(messageUpdateInvokeHelper));
}
private void UpdateMessage()
{
message = "UpdateMessage Called!";
display = "none";
StateHasChanged();
}
}
@inject IJSRuntime JS
<li>
@message
<button @onclick="InteropCall" style="display:@display">InteropCall</button>
</li>
@code {
private string message = "Select one of these list item buttons.";
private string display = "inline-block";
private MessageUpdateInvokeHelper messageUpdateInvokeHelper;
protected override void OnInitialized()
{
messageUpdateInvokeHelper = new MessageUpdateInvokeHelper(UpdateMessage);
}
protected async Task InteropCall()
{
await JS.InvokeVoidAsync("updateMessageCaller",
DotNetObjectReference.Create(messageUpdateInvokeHelper));
}
private void UpdateMessage()
{
message = "UpdateMessage Called!";
display = "none";
StateHasChanged();
}
}
StateHasChanged
wird aufgerufen, um die Benutzeroberfläche zu aktualisieren, wenn message
in UpdateMessage
festgelegt wird. Wenn StateHasChanged
nicht aufgerufen wird, kann Blazor nicht wissen, dass die Benutzeroberfläche aktualisiert werden soll, wenn Action aufgerufen wird.
Die folgende übergeordnete Komponente enthält vier Listenelemente, die jeweils eine Instanz der ListItem1
-Komponente sind.
CallDotnet6.razor
:
@page "/call-dotnet-6"
<PageTitle>Call .NET 6</PageTitle>
<h1>Call .NET Example 6</h1>
<ul>
<ListItem1 />
<ListItem1 />
<ListItem1 />
<ListItem1 />
</ul>
CallDotnet6.razor
:
@page "/call-dotnet-6"
<PageTitle>Call .NET 6</PageTitle>
<h1>Call .NET Example 6</h1>
<ul>
<ListItem1 />
<ListItem1 />
<ListItem1 />
<ListItem1 />
</ul>
CallDotNetExample6.razor
:
@page "/call-dotnet-example-6"
<h1>Call .NET Example 6</h1>
<ul>
<ListItem1 />
<ListItem1 />
<ListItem1 />
<ListItem1 />
</ul>
CallDotNetExample6.razor
:
@page "/call-dotnet-example-6"
<h1>Call .NET Example 6</h1>
<ul>
<ListItem1 />
<ListItem1 />
<ListItem1 />
<ListItem1 />
</ul>
CallDotNetExample6.razor
:
@page "/call-dotnet-example-6"
<h1>Call .NET Example 6</h1>
<ul>
<ListItem1 />
<ListItem1 />
<ListItem1 />
<ListItem1 />
</ul>
CallDotNetExample6.razor
:
@page "/call-dotnet-example-6"
<h1>Call .NET Example 6</h1>
<ul>
<ListItem1 />
<ListItem1 />
<ListItem1 />
<ListItem1 />
</ul>
Die folgende Abbildung zeigt die gerenderte übergeordnete Komponente, nachdem die zweite InteropCall
-Schaltfläche ausgewählt wurde:
- Die zweite
ListItem1
-Komponente hat die MeldungUpdateMessage Called!
angezeigt. - Die Schaltfläche
InteropCall
für die zweiteListItem1
-Komponente ist nicht sichtbar, da die CSS-Eigenschaftdisplay
der Schaltfläche aufnone
festgelegt ist.
.NET-Methode der Komponenteninstanz, die von DotNetObjectReference
aufgerufen wird, die einer Elementeigenschaft zugewiesen ist
Die Zuweisung einer DotNetObjectReference zu einer Eigenschaft eines HTML-Elements ermöglicht das Aufrufen von .NET-Methoden für eine Komponenteninstanz:
- Ein Elementverweis wird aufgezeichnet (ElementReference).
- In der Methode
OnAfterRender{Async}
der Komponente wird eine JavaScript -Funktion (JS) mit dem Elementverweis und der Komponenteninstanz als DotNetObjectReference aufgerufen. Die JS-Funktion fügt die DotNetObjectReference an das Element in einer Eigenschaft an. - Wenn ein Elementereignis in JS (z. B.
onclick
) aufgerufen wird, wird die angefügte DotNetObjectReference des Elements zum Aufrufen einer .NET-Methode verwendet.
Ähnlich wie bei dem ansatz, der im Abschnitt ".NET-Hilfsklasse der Komponenteninstanz" beschrieben wird, ist dieser Ansatz in Szenarien hilfreich, in denen die Verwendung statischer .NET-Methoden nicht anwendbar ist:
- Auf einer Seite werden mehrere Komponenten desselben Typs gerendert.
- In serverseitigen Apps, in denen mehrere Benutzer*innen gleichzeitig die gleiche Komponente verwenden.
- Die .NET-Methode wird aus einem JS-Ereignis (z. B.
onclick
) und nicht aus einem Blazor-Ereignis (z. B.@onclick
) aufgerufen.
Im folgenden Beispiel:
- Die Komponente enthält mehrere
ListItem2
-Komponenten, bei denen es sich um freigegebene Komponenten handelt. - Jede
ListItem2
Komponente besteht aus einer Listenelementnachricht<span>
und einer zweiten<span>
mit einerdisplay
CSS-Eigenschaft, die für die Anzeige aufinline-block
festgelegt ist. - Wenn ein
ListItem2
Komponentenlistenelement ausgewählt ist, ändert dieUpdateMessage
-Methode diesesListItem2
den Listenelementtext im ersten<span>
und blendet den zweiten<span>
aus, indem sie seinedisplay
-Eigenschaft aufnone
festlegt.
Mit der folgenden assignDotNetHelper
JS-Funktion wird die DotNetObjectReference einem Element in einer Eigenschaft mit dem Namen dotNetHelper
zugewiesen: Die folgende interopCall
JS-Funktion verwendet die DotNetObjectReference für das übergebene Element zum Aufrufen einer .NET-Methode mit dem Namen UpdateMessage
:
ListItem2.razor.js
:
export function assignDotNetHelper(element, dotNetHelper) {
element.dotNetHelper = dotNetHelper;
}
export async function interopCall(element) {
await element.dotNetHelper.invokeMethodAsync('UpdateMessage');
}
ListItem2.razor.js
:
export function assignDotNetHelper(element, dotNetHelper) {
element.dotNetHelper = dotNetHelper;
}
export async function interopCall(element) {
await element.dotNetHelper.invokeMethodAsync('UpdateMessage');
}
<script>
window.assignDotNetHelper = (element, dotNetHelper) => {
element.dotNetHelper = dotNetHelper;
}
window.interopCall = async (element) => {
await element.dotNetHelper.invokeMethodAsync('UpdateMessage');
}
</script>
Hinweis
Allgemeine Anleitungen zum JSSpeicherort und zu unseren Empfehlungen für Produktions-Apps finden Sie unter JavaScript-Speicherort in ASP.NET CoreBlazor-Apps in ASP.NET Core.
Im vorherigen Beispiel ist der Variablenname dotNetHelper
willkürlich gewählt und kann in einen beliebigen Namen geändert werden.
Die folgende ListItem2
-Komponente ist eine freigegebene Komponente, die in einer übergeordneten Komponente mehrmals verwendet werden kann und Listenelemente (<li>...</li>
) für eine HTML-Liste (<ul>...</ul>
oder <ol>...</ol>
) erstellt.
Jede ListItem2
Komponenteninstanz ruft die assignDotNetHelper
JS-Funktion in OnAfterRenderAsync
mit einer Elementreferenz (das erste <span>
-Element des Listenelements) und die Komponenteninstanz als eine DotNetObjectReference auf.
Wenn die Nachricht einer ListItem2
-Komponente <span>
ausgewählt ist, wird interopCall
aufgerufen und dadurch das <span>
-Element als Parameter (this
) übergeben, der die UpdateMessage
-.NET-Methode aufruft. In UpdateMessage
wird StateHasChanged
aufgerufen, um die Benutzeroberfläche zu aktualisieren, wenn message
festgelegt und die Eigenschaft display
des zweiten <span>
aktualisiert wird. Wenn StateHasChanged
nicht aufgerufen wird, kann Blazor nicht wissen, dass die Benutzeroberfläche aktualisiert werden soll, wenn die Methode aufgerufen wird.
Die DotNetObjectReference wird verworfen, wenn die Komponente verworfen wird.
ListItem2.razor
:
@inject IJSRuntime JS
@implements IAsyncDisposable
<li>
<span style="font-weight:bold;color:@color" @ref="elementRef"
@onclick="CallJSToInvokeDotnet">
@message
</span>
<span style="display:@display">
Not Updated Yet!
</span>
</li>
@code {
private IJSObjectReference? module;
private DotNetObjectReference<ListItem2>? objRef;
private ElementReference elementRef;
private string display = "inline-block";
private string message = "Select one of these list items.";
private string color = "initial";
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
module = await JS.InvokeAsync<IJSObjectReference>("import",
"./Components/ListItem2.razor.js");
objRef = DotNetObjectReference.Create(this);
await module.InvokeVoidAsync("assignDotNetHelper", elementRef, objRef);
}
}
public async void CallJSToInvokeDotnet()
{
if (module is not null)
{
await module.InvokeVoidAsync("interopCall", elementRef);
}
}
[JSInvokable]
public void UpdateMessage()
{
message = "UpdateMessage Called!";
display = "none";
color = "MediumSeaGreen";
StateHasChanged();
}
async ValueTask IAsyncDisposable.DisposeAsync()
{
if (module is not null)
{
await module.DisposeAsync();
}
objRef?.Dispose();
}
}
@inject IJSRuntime JS
@implements IAsyncDisposable
<li>
<span style="font-weight:bold;color:@color" @ref="elementRef"
@onclick="CallJSToInvokeDotnet">
@message
</span>
<span style="display:@display">
Not Updated Yet!
</span>
</li>
@code {
private IJSObjectReference? module;
private DotNetObjectReference<ListItem2>? objRef;
private ElementReference elementRef;
private string display = "inline-block";
private string message = "Select one of these list items.";
private string color = "initial";
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
module = await JS.InvokeAsync<IJSObjectReference>("import",
"./Components/ListItem2.razor.js");
objRef = DotNetObjectReference.Create(this);
await module.InvokeVoidAsync("assignDotNetHelper", elementRef, objRef);
}
}
public async void CallJSToInvokeDotnet()
{
if (module is not null)
{
await module.InvokeVoidAsync("interopCall", elementRef);
}
}
[JSInvokable]
public void UpdateMessage()
{
message = "UpdateMessage Called!";
display = "none";
color = "MediumSeaGreen";
StateHasChanged();
}
async ValueTask IAsyncDisposable.DisposeAsync()
{
if (module is not null)
{
await module.DisposeAsync();
}
objRef?.Dispose();
}
}
@inject IJSRuntime JS
<li>
<span @ref="elementRef" onclick="interopCall(this)">@message</span>
<span style="display:@display">Not Updated Yet!</span>
</li>
@code {
private DotNetObjectReference<ListItem2>? objRef;
private ElementReference elementRef;
private string display = "inline-block";
private string message = "Select one of these list items.";
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
objRef = DotNetObjectReference.Create(this);
await JS.InvokeVoidAsync("assignDotNetHelper", elementRef, objRef);
}
}
[JSInvokable]
public void UpdateMessage()
{
message = "UpdateMessage Called!";
display = "none";
StateHasChanged();
}
public void Dispose() => objRef?.Dispose();
}
@inject IJSRuntime JS
<li>
<span @ref="elementRef" onclick="interopCall(this)">@message</span>
<span style="display:@display">Not Updated Yet!</span>
</li>
@code {
private DotNetObjectReference<ListItem2>? objRef;
private ElementReference elementRef;
private string display = "inline-block";
private string message = "Select one of these list items.";
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
objRef = DotNetObjectReference.Create(this);
await JS.InvokeVoidAsync("assignDotNetHelper", elementRef, objRef);
}
}
[JSInvokable]
public void UpdateMessage()
{
message = "UpdateMessage Called!";
display = "none";
StateHasChanged();
}
public void Dispose() => objRef?.Dispose();
}
@inject IJSRuntime JS
<li>
<span @ref="elementRef" onclick="interopCall(this)">@message</span>
<span style="display:@display">Not Updated Yet!</span>
</li>
@code {
private DotNetObjectReference<ListItem2> objRef;
private ElementReference elementRef;
private string display = "inline-block";
private string message = "Select one of these list items.";
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
objRef = DotNetObjectReference.Create(this);
await JS.InvokeVoidAsync("assignDotNetHelper", elementRef, objRef);
}
}
[JSInvokable]
public void UpdateMessage()
{
message = "UpdateMessage Called!";
display = "none";
StateHasChanged();
}
public void Dispose() => objRef?.Dispose();
}
@inject IJSRuntime JS
<li>
<span @ref="elementRef" onclick="interopCall(this)">@message</span>
<span style="display:@display">Not Updated Yet!</span>
</li>
@code {
private DotNetObjectReference<ListItem2> objRef;
private ElementReference elementRef;
private string display = "inline-block";
private string message = "Select one of these list items.";
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
objRef = DotNetObjectReference.Create(this);
await JS.InvokeVoidAsync("assignDotNetHelper", elementRef, objRef);
}
}
[JSInvokable]
public void UpdateMessage()
{
message = "UpdateMessage Called!";
display = "none";
StateHasChanged();
}
public void Dispose() => objRef?.Dispose();
}
Die folgende übergeordnete Komponente enthält vier Listenelemente, die jeweils eine Instanz der ListItem2
-Komponente sind.
CallDotnet7.razor
:
@page "/call-dotnet-7"
<PageTitle>Call .NET 7</PageTitle>
<h1>Call .NET Example 7</h1>
<ul>
<ListItem2 />
<ListItem2 />
<ListItem2 />
<ListItem2 />
</ul>
CallDotnet7.razor
:
@page "/call-dotnet-7"
<PageTitle>Call .NET 7</PageTitle>
<h1>Call .NET Example 7</h1>
<ul>
<ListItem2 />
<ListItem2 />
<ListItem2 />
<ListItem2 />
</ul>
CallDotNetExample7.razor
:
@page "/call-dotnet-example-7"
<h1>Call .NET Example 7</h1>
<ul>
<ListItem2 />
<ListItem2 />
<ListItem2 />
<ListItem2 />
</ul>
CallDotNetExample7.razor
:
@page "/call-dotnet-example-7"
<h1>Call .NET Example 7</h1>
<ul>
<ListItem2 />
<ListItem2 />
<ListItem2 />
<ListItem2 />
</ul>
CallDotNetExample7.razor
:
@page "/call-dotnet-example-7"
<h1>Call .NET Example 7</h1>
<ul>
<ListItem2 />
<ListItem2 />
<ListItem2 />
<ListItem2 />
</ul>
CallDotNetExample7.razor
:
@page "/call-dotnet-example-7"
<h1>Call .NET Example 7</h1>
<ul>
<ListItem2 />
<ListItem2 />
<ListItem2 />
<ListItem2 />
</ul>
Synchrone JS-Interoperabilität in clientseitigen Komponenten
Dieser Abschnitt gilt nur für clientseitige Komponenten.
JS-Interoperabilitätsaufrufe sind asynchron, unabhängig davon, ob der aufgerufene Code synchron oder asynchron ist. Die Aufrufe sind asynchron, um sicherzustellen, dass die Komponenten mit den serverseitigen und clientseitigen Rendermodi kompatibel sind. Auf dem Server müssen alle JS-Interop-Aufrufe asynchron sein, da sie über eine Netzwerkverbindung gesendet werden.
Wenn Ihre Komponente ausschließlich in WebAssembly ausgeführt wird, können Sie sich für synchrone JS-Interop-Aufrufe entscheiden. Dies ist mit etwas weniger Mehraufwand verbunden als asynchrone Aufrufe und kann zu weniger Renderingzyklen führen, da es keinen Zwischenzustand gibt, während auf die Ergebnisse gewartet wird.
Um in einer clientseitigen Komponente einen synchronen Aufruf von JavaScript an .NET zu richten, verwenden Sie DotNet.invokeMethod
anstelle von DotNet.invokeMethodAsync
.
Synchrone Aufrufe funktionieren unter folgenden Voraussetzungen:
JavaScript-Speicherort
Laden Sie JavaScript (JS)-Code mithilfe eines der Ansätze, die im Artikel zum JavaScript-Speicherortbeschrieben werden:
- Laden eines Skripts im
<head>
-Markup (im Allgemeinen nicht empfohlen) - Laden eines Skripts im
<body>
-Markup - Laden eines Skripts aus einer externen JavaScript-Datei (
.js
), die mit einer Komponente verbunden ist - Laden eines Skripts aus einer externen JavaScript-Datei (
.js
) - Einfügen eines Skripts vor oder nach dem Start von Blazor
Die Verwendung von JS-Modulen zum Laden von JS wird in diesem Artikel im Abschnitt JavaScript-Isolation in JavaScript-Modulen beschrieben.
Warnung
Platzieren Sie ein <script>
-Tag nur in einer Komponentendatei (.razor
), wenn die Komponente garantiert statisches serverseitiges Rendering (static sSR) verwendet, da das <script>
-Tag nicht dynamisch aktualisiert werden kann.
Warnung
Platzieren Sie kein <script>
-Tag in einer Komponentendatei (.razor
), weil das <script>
-Tag nicht dynamisch aktualisiert werden kann.
JavaScript-Isolierung in JavaScript-Modulen
Blazor aktiviert die JavaScript-Isolation (JS) in JavaScript-Standardmodulen (ECMAScript-Spezifikation). Das Laden von JavaScript-Modulen funktioniert in Blazor genauso wie bei anderen Arten von Web-Apps, und Sie können die Definition von Modulen in Ihrer App anpassen. Eine Anleitung zur Verwendung von JavaScript-Modulen finden Sie in den MDN Web Docs: JavaScript modules.
JS-Isolierung bietet die folgenden Vorteile:
- Importiertes JS verschmutzt nicht mehr den globalen Namespace.
- Consumer einer Bibliothek und Komponenten müssen nicht das zugehörige JS importieren.
Weitere Informationen finden Sie unter Aufrufen von JavaScript-Funktionen über .NET-Methoden in Blazor in ASP.NET Core.
Der dynamische Import mit dem import()
-Operator wird mit ASP.NET Core und Blazor unterstützt:
if ({CONDITION}) import("/additionalModule.js");
Im vorherigen Beispiel steht der Platzhalter {CONDITION}
für eine bedingte Überprüfung, mit der festgestellt wird, ob das Modul geladen werden soll.
Informationen zur Browserkompatibilität finden Sie unter Can I use: JavaScript modules: dynamic import.
Vermeiden von Objektzirkelbezügen
Objekte, die Zirkelbezüge enthalten, können auf dem Client für folgende Vorgänge nicht serialisiert werden:
- .NET-Methodenaufrufe.
- JavaScript-Methodenaufrufe von C#, wenn der Rückgabetyp Zirkelbezüge enthält.
Bytearrayunterstützung
Blazor unterstützt optimiertes Bytearray-JavaScript (JS)-Interop, mit dem sich das Codieren/Decodieren von Bytearrays in Base64 vermeiden lässt. Im folgenden Beispiel wird JS-Interop verwendet, um ein Bytearray an .NET zu übergeben.
Stellen Sie eine sendByteArray
JS-Funktion bereit. Die Funktion wird statisch durch eine Schaltfläche in der Komponente aufgerufen, wobei der Assemblynamenparameter im invokeMethodAsync
-Aufruf enthalten ist, und gibt keinen Wert zurück:
CallDotnet8.razor.js
:
export function sendByteArray() {
const data = new Uint8Array([0x45, 0x76, 0x65, 0x72, 0x79, 0x74, 0x68, 0x69,
0x6e, 0x67, 0x27, 0x73, 0x20, 0x73, 0x68, 0x69, 0x6e, 0x79, 0x2c,
0x20, 0x43, 0x61, 0x70, 0x74, 0x61, 0x69, 0x6e, 0x2e, 0x20, 0x4e,
0x6f, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x66, 0x72, 0x65, 0x74, 0x2e]);
DotNet.invokeMethodAsync('BlazorSample', 'ReceiveByteArray', data)
.then(str => {
alert(str);
});
}
export function addHandlers() {
const btn = document.getElementById("btn");
btn.addEventListener("click", sendByteArray);
}
<script>
window.sendByteArray = () => {
const data = new Uint8Array([0x45,0x76,0x65,0x72,0x79,0x74,0x68,0x69,
0x6e,0x67,0x27,0x73,0x20,0x73,0x68,0x69,0x6e,0x79,0x2c,
0x20,0x43,0x61,0x70,0x74,0x61,0x69,0x6e,0x2e,0x20,0x4e,
0x6f,0x74,0x20,0x74,0x6f,0x20,0x66,0x72,0x65,0x74,0x2e]);
DotNet.invokeMethodAsync('BlazorSample', 'ReceiveByteArray', data)
.then(str => {
alert(str);
});
};
</script>
Hinweis
Allgemeine Anleitungen zu JS Standort und unseren Empfehlungen für Produktions-Apps finden Sie unter JavaScript-Speicherort in ASP.NET Core Blazor -Apps.
CallDotnet8.razor
:
@page "/call-dotnet-8"
@using System.Text
@implements IAsyncDisposable
@inject IJSRuntime JS
<PageTitle>Call .NET 8</PageTitle>
<h1>Call .NET Example 8</h1>
<p>
<button id="btn">Send Bytes</button>
</p>
<p>
Quote ©2005 <a href="https://www.uphe.com">Universal Pictures</a>:
<a href="https://www.uphe.com/movies/serenity-2005">Serenity</a><br>
<a href="https://www.imdb.com/name/nm0821612/">Jewel Staite on IMDB</a>
</p>
@code {
private IJSObjectReference? module;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
module = await JS.InvokeAsync<IJSObjectReference>("import",
"./Components/Pages/CallDotnet8.razor.js");
await module.InvokeVoidAsync("addHandlers");
}
}
[JSInvokable]
public static Task<string> ReceiveByteArray(byte[] receivedBytes) =>
Task.FromResult(Encoding.UTF8.GetString(receivedBytes, 0,
receivedBytes.Length));
async ValueTask IAsyncDisposable.DisposeAsync()
{
if (module is not null)
{
await module.DisposeAsync();
}
}
}
CallDotnet8.razor
:
@page "/call-dotnet-8"
@using System.Text
@implements IAsyncDisposable
@inject IJSRuntime JS
<PageTitle>Call .NET 8</PageTitle>
<h1>Call .NET Example 8</h1>
<p>
<button id="btn">Send Bytes</button>
</p>
<p>
Quote ©2005 <a href="https://www.uphe.com">Universal Pictures</a>:
<a href="https://www.uphe.com/movies/serenity-2005">Serenity</a><br>
<a href="https://www.imdb.com/name/nm0821612/">Jewel Staite on IMDB</a>
</p>
@code {
private IJSObjectReference? module;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
module = await JS.InvokeAsync<IJSObjectReference>("import",
"./Components/Pages/CallDotnet8.razor.js");
await module.InvokeVoidAsync("addHandlers");
}
}
[JSInvokable]
public static Task<string> ReceiveByteArray(byte[] receivedBytes) =>
Task.FromResult(Encoding.UTF8.GetString(receivedBytes, 0,
receivedBytes.Length));
async ValueTask IAsyncDisposable.DisposeAsync()
{
if (module is not null)
{
await module.DisposeAsync();
}
}
}
CallDotNetExample8.razor
:
@page "/call-dotnet-example-8"
@using System.Text
<PageTitle>Call .NET 8</PageTitle>
<h1>Call .NET Example 8</h1>
<p>
<button onclick="sendByteArray()">Send Bytes</button>
</p>
<p>
Quote ©2005 <a href="https://www.uphe.com">Universal Pictures</a>:
<a href="https://www.uphe.com/movies/serenity-2005">Serenity</a><br>
<a href="https://www.imdb.com/name/nm0821612/">Jewel Staite on IMDB</a>
</p>
@code {
[JSInvokable]
public static Task<string> ReceiveByteArray(byte[] receivedBytes)
{
return Task.FromResult(
Encoding.UTF8.GetString(receivedBytes, 0, receivedBytes.Length));
}
}
CallDotNetExample8.razor
:
@page "/call-dotnet-example-8"
@using System.Text
<h1>Call .NET Example 8</h1>
<p>
<button onclick="sendByteArray()">Send Bytes</button>
</p>
<p>
Quote ©2005 <a href="https://www.uphe.com">Universal Pictures</a>:
<a href="https://www.uphe.com/movies/serenity-2005">Serenity</a><br>
<a href="https://www.imdb.com/name/nm0821612/">Jewel Staite on IMDB</a>
</p>
@code {
[JSInvokable]
public static Task<string> ReceiveByteArray(byte[] receivedBytes)
{
return Task.FromResult(
Encoding.UTF8.GetString(receivedBytes, 0, receivedBytes.Length));
}
}
Informationen zur Verwendung eines Bytearrays beim Aufruf von JavaScript aus .NET finden Sie unter Aufrufen von JavaScript-Funktionen über .NET-Methoden in Blazor in ASP.NET Core.
Streamen von JavaScript an .NET
Blazor unterstützt das direkte Streamen von Daten aus JavaScript an .NET. Streams werden mithilfe der Microsoft.JSInterop.IJSStreamReference
-Schnittstelle angefordert.
Microsoft.JSInterop.IJSStreamReference.OpenReadStreamAsync
gibt Stream zurück und verwendet die folgenden Parameter:
maxAllowedSize
: Maximale Byteanzahl für Lesevorgänge von JavaScript, die Standardeinstellung ist 512.000 Byte, wenn nichts anderes angegeben ist.cancellationToken
: Ein CancellationToken zum Abbrechen des Lesevorgangs.
In JavaScript:
function streamToDotNet() {
return new Uint8Array(10000000);
}
In C#-Code:
var dataReference =
await JS.InvokeAsync<IJSStreamReference>("streamToDotNet");
using var dataReferenceStream =
await dataReference.OpenReadStreamAsync(maxAllowedSize: 10_000_000);
var outputPath = Path.Combine(Path.GetTempPath(), "file.txt");
using var outputFileStream = File.OpenWrite(outputPath);
await dataReferenceStream.CopyToAsync(outputFileStream);
Im vorherigen Beispiel:
JS
ist eine eingefügte IJSRuntime-Instanz. IJSRuntime wird vom Blazor-Framework registriert.dataReferenceStream
wird auf den Datenträger (infile.txt
) geschrieben, auf dem sich der aktuelle temporäre Ordner (GetTempPath) des Benutzers befindet.
Unter Aufrufen von JavaScript-Funktionen über .NET-Methoden in Blazor in ASP.NET Core wird der umgekehrte Vorgang behandelt, nämlich das Streamen aus .NET in JavaScript mithilfe von DotNetStreamReference.
Unter Blazor-Dateiuploads in ASP.NET Core wird das Hochladen einer Datei in Blazor behandelt. Ein Formularbeispiel, das <textarea>
-Daten in einer serverseitigen Komponente streamt, finden Sie unter Problembehandlung bei ASP.NET Core Blazor-Formularen.
JavaScript-Interoperabilität mit [JSImport]
/[JSExport]
Dieser Abschnitt gilt für clientseitige Komponenten.
Als Alternative zur Interaktion mit JavaScript (JS) in clientseitigen Komponenten, die den JS-Interop-Mechanismus von Blazor basierend auf der IJSRuntime-Schnittstelle verwenden, ist auch eine JS[JSImport]
/[JSExport]
-Interop-API für Apps verfügbar, die auf .NET 7 oder höher ausgerichtet sind.
Weitere Informationen finden Sie unter JavaScript-Interoperabilität mit JSImport/JSExport mit ASP.NET Core-Blazor.
Löschen von Objektverweisen bei JavaScript-Interoperabilität
Alle Beispiele im Artikel zur JavaScript-Interoperabilität (JS) veranschaulichen typische Muster zum Löschen von Objekten:
Wenn Sie .NET aus JS aufrufen, wie in diesem Artikel beschrieben, löschen Sie einen erstellten DotNetObjectReference entweder aus .NET oder aus JS, um .NET-Arbeitsspeicherverluste zu vermeiden.
Wenn Sie JS aus .NET aufrufen, wie unter Aufrufen von JavaScript-Funktionen über .NET-Methoden in ASP.NET Core Blazor beschrieben, löschen Sie alle erstellten IJSObjectReference/IJSInProcessObjectReference/
JSObjectReference
-Elemente entweder aus .NET oder aus JS, um JS-Arbeitsspeicherverluste zu vermeiden.
Objektverweise bei JS-Interoperabilität werden als Zuordnung implementiert, die durch einen Bezeichner auf der Seite des JS-Interoperabilitätsaufrufs definiert ist, der den Verweis erstellt. Wenn die Objektlöschung von .NET oder JS aus initiiert wird, entfernt Blazor den Eintrag aus der Zuordnung, und das Objekt kann durch die Garbage Collection gelöscht werden, sofern kein anderer starker Verweis auf das Objekt vorhanden ist.
Sie sollten immer mindestens die auf .NET-Seite erstellten Objekte löschen, um Verluste im von .NET verwalteten Arbeitsspeicher zu vermeiden.
DOM-Bereinigungsvorgänge während der Beseitigung von Komponenten
Weitere Informationen finden Sie unter JavaScript-Interoperabilität von Blazor in ASP.NET Core (JS-Interoperabilität).
JavaScript-Interopaufrufe ohne Verbindung
Weitere Informationen finden Sie unter JavaScript-Interoperabilität von Blazor in ASP.NET Core (JS-Interoperabilität).
Zusätzliche Ressourcen
- Aufrufen von JavaScript-Funktionen über .NET-Methoden in in ASP.NET CoreBlazor
InteropComponent.razor
-Beispiel (GitHub-Repositorydotnet/AspNetCore
,main
-Branch): Dermain
-Branch entspricht der aktuellen Entwicklung der Produkteinheit für das nächste Release von ASP.NET Core. Zum Auswählen der Verzweigung für eine andere Version (z. B. wenn der Platzhalter die{VERSION}
Releaseversion ist), verwenden Sie die Dropdownliste "Switch Branches" oder "Tags",release/{VERSION}
um die Verzweigung auszuwählen. Verwenden Sie für einen Zweig, der nicht mehr vorhanden ist, die Registerkarte "Kategorien " zum Suchen der API (z. Bv7.0.0
. ).- Interaktion mit dem DOM
- GitHub-Repository mit Blazor-Beispielen (
dotnet/blazor-samples
) (Informationen zum Herunterladen) - Behandeln von Fehlern in ASP.NET Core Blazor-Apps (Abschnitt JavaScript-Interop)
- Bedrohungsminderung: Über den Browser aufgerufene .NET-Methoden