Memanggil metode .NET dari fungsi JavaScript di ASP.NET Core Blazor
Catatan
Ini bukan versi terbaru dari artikel ini. Untuk rilis saat ini, lihat versi .NET 9 dari artikel ini.
Peringatan
Versi ASP.NET Core ini tidak lagi didukung. Untuk informasi selengkapnya, lihat Kebijakan Dukungan .NET dan .NET Core. Untuk rilis saat ini, lihat versi .NET 8 dari artikel ini.
Penting
Informasi ini berkaitan dengan produk pra-rilis yang mungkin dimodifikasi secara substansial sebelum dirilis secara komersial. Microsoft tidak memberikan jaminan, tersirat maupun tersurat, sehubungan dengan informasi yang diberikan di sini.
Untuk rilis saat ini, lihat versi .NET 9 dari artikel ini.
Artikel ini menjelaskan cara memanggil metode .NET dari JavaScript (JS).
Untuk informasi tentang cara memanggil JS fungsi dari .NET, lihat Memanggil fungsi JavaScript dari metode .NET di ASP.NET Core Blazor.
Memanggil metode .NET statis
Untuk memanggil metode .NET statis dari JavaScript (JS), gunakan JS fungsi:
DotNet.invokeMethodAsync
(disarankan): Asinkron untuk komponen sisi server dan sisi klien.DotNet.invokeMethod
: Sinkron hanya untuk komponen sisi klien.
Berikan nama rakitan yang berisi metode , pengidentifikasi metode .NET statis, dan argumen apa pun.
Dalam contoh berikut:
- Tempat
{ASSEMBLY NAME}
penampung adalah nama rakitan aplikasi. - Tempat
{.NET METHOD ID}
penampung adalah pengidentifikasi metode .NET. - Tempat
{ARGUMENTS}
penampung adalah argumen opsional yang dipisahkan koma untuk diteruskan ke metode , yang masing-masing harus dapat diserialisasikan JSON.
DotNet.invokeMethodAsync('{ASSEMBLY NAME}', '{.NET METHOD ID}', {ARGUMENTS});
DotNet.invokeMethodAsync
mengembalikan yang JS Promise
mewakili hasil operasi. DotNet.invokeMethod
(komponen sisi klien) mengembalikan hasil operasi.
Penting
Untuk komponen sisi server, kami merekomendasikan fungsi asinkron (invokeMethodAsync
) melalui versi sinkron (invokeMethod
).
Metode .NET harus publik, statis, dan memiliki [JSInvokable]
atribut .
Dalam contoh berikut:
- Tempat
{<T>}
penampung menunjukkan jenis pengembalian, yang hanya diperlukan untuk metode yang mengembalikan nilai. - Tempat
{.NET METHOD ID}
penampung adalah pengidentifikasi metode.
@code {
[JSInvokable]
public static Task{<T>} {.NET METHOD ID}()
{
...
}
}
Catatan
Memanggil metode generik terbuka tidak didukung dengan metode .NET statis tetapi didukung dengan metode instans. Untuk informasi selengkapnya, lihat bagian Memanggil metode kelas generik .NET.
Dalam komponen berikut, ReturnArrayAsync
metode C# mengembalikan int
array. Atribut [JSInvokable]
diterapkan ke metode , yang membuat metode dapat dipanggil oleh JS.
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);
}
Fungsi menambahkan addHandlers
JS click
peristiwa ke tombol . Fungsi returnArrayAsync
JS ini ditetapkan sebagai handler.
Fungsi ini returnArrayAsync
JS memanggil ReturnArrayAsync
metode .NET dari komponen, yang mencatat hasilnya ke konsol alat pengembang web browser. BlazorSample
adalah nama rakitan aplikasi.
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);
}
Fungsi menambahkan addHandlers
JS click
peristiwa ke tombol . Fungsi returnArrayAsync
JS ini ditetapkan sebagai handler.
Fungsi ini returnArrayAsync
JS memanggil ReturnArrayAsync
metode .NET dari komponen, yang mencatat hasilnya ke konsol alat pengembang web browser. BlazorSample
adalah nama rakitan aplikasi.
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 });
}
}
Atribut <button>
HTML elemen onclick
adalah penugasan penanganan aktivitas JavaScript onclick
untuk memproses click
peristiwa, bukan Blazor@onclick
atribut direktif. Fungsi returnArrayAsync
JS ini ditetapkan sebagai handler.
Fungsi berikut returnArrayAsync
JS , memanggil ReturnArrayAsync
metode .NET dari komponen, yang mencatat hasilnya ke konsol alat pengembang web browser. BlazorSample
adalah nama rakitan aplikasi.
<script>
window.returnArrayAsync = () => {
DotNet.invokeMethodAsync('BlazorSample', 'ReturnArrayAsync')
.then(data => {
console.log(data);
});
};
</script>
Catatan
Untuk panduan umum tentang JS lokasi dan rekomendasi kami untuk aplikasi produksi, lihat Lokasi JavaScript di aplikasi ASP.NET CoreBlazor.
Saat tombol Trigger .NET static method
dipilih, output konsol alat pengembang browser menampilkan data array. Format output sedikit berbeda di antara browser. Output berikut menunjukkan format yang digunakan oleh Microsoft Edge:
Array(3) [ 11, 12, 13 ]
Teruskan data ke metode .NET saat memanggil invokeMethodAsync
fungsi dengan meneruskan data sebagai argumen.
Untuk menunjukkan meneruskan data ke .NET, teruskan posisi awal ke ReturnArrayAsync
metode di mana metode dipanggil dalam JS:
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>
Metode yang dapat ReturnArrayAsync
dipanggil komponen menerima posisi awal dan membangun array darinya. Array dikembalikan untuk pengelogan ke konsol:
[JSInvokable]
public static Task<int[]> ReturnArrayAsync(int startPosition) =>
Task.FromResult(Enumerable.Range(startPosition, 3).ToArray());
Setelah aplikasi dikompresi ulang dan browser di-refresh, output berikut muncul di konsol browser saat tombol dipilih:
Array(3) [ 14, 15, 16 ]
Pengidentifikasi metode .NET untuk JS panggilan adalah nama metode .NET, tetapi Anda dapat menentukan pengidentifikasi yang berbeda menggunakan [JSInvokable]
konstruktor atribut . Dalam contoh berikut, DifferentMethodName
adalah pengidentifikasi metode yang ditetapkan untuk metode :ReturnArrayAsync
[JSInvokable("DifferentMethodName")]
Dalam panggilan ke DotNet.invokeMethodAsync
(komponen sisi server atau sisi klien) atau DotNet.invokeMethod
(hanya komponen sisi klien), panggil DifferentMethodName
untuk menjalankan ReturnArrayAsync
metode .NET:
DotNet.invokeMethodAsync('BlazorSample', 'DifferentMethodName');
DotNet.invokeMethod('BlazorSample', 'DifferentMethodName');
(hanya komponen sisi klien)
Catatan
Contoh ReturnArrayAsync
metode di bagian ini mengembalikan hasil tanpa Task menggunakan C# async
eksplisit dan await
kata kunci. Metode pengodean dengan async
dan await
khas metode yang menggunakan await
kata kunci untuk mengembalikan nilai operasi asinkron.
ReturnArrayAsync
metode yang terdiri dari async
kata kunci dan await
:
[JSInvokable]
public static async Task<int[]> ReturnArrayAsync() =>
await Task.FromResult(new int[] { 11, 12, 13 });
Untuk informasi selengkapnya, lihat Pemrograman asinkron dengan asinkron dan tunggu di panduan C#.
Buat objek JavaScript dan referensi data untuk diteruskan ke .NET
Panggil DotNet.createJSObjectReference(jsObject)
untuk membuat JS referensi objek sehingga dapat diteruskan ke .NET, di mana jsObject
digunakan JS Object
untuk membuat JS referensi objek. Contoh berikut meneruskan referensi ke objek yang tidak dapat diserialisasikan window
ke .NET, yang menerimanya dalam ReceiveWindowObject
metode C# sebagai IJSObjectReference:
DotNet.invokeMethodAsync('{ASSEMBLY NAME}', 'ReceiveWindowObject',
DotNet.createJSObjectReference(window));
[JSInvokable]
public static void ReceiveWindowObject(IJSObjectReference objRef)
{
...
}
Dalam contoh sebelumnya, {ASSEMBLY NAME}
tempat penampung adalah namespace aplikasi.
Catatan
Contoh sebelumnya tidak memerlukan pembuangan JSObjectReference
, karena referensi ke window
objek tidak ditahan di JS.
Mempertahankan referensi ke JSObjectReference
perlu membuangnya untuk menghindari kebocoran JS memori pada klien. Contoh berikut merefaktor kode sebelumnya untuk mengambil referensi ke JSObjectReference
, diikuti dengan panggilan ke untuk DotNet.disposeJSObjectReference()
membuang referensi:
var jsObjectReference = DotNet.createJSObjectReference(window);
DotNet.invokeMethodAsync('{ASSEMBLY NAME}', 'ReceiveWindowObject', jsObjectReference);
DotNet.disposeJSObjectReference(jsObjectReference);
Dalam contoh sebelumnya, {ASSEMBLY NAME}
tempat penampung adalah namespace aplikasi.
Panggil DotNet.createJSStreamReference(streamReference)
untuk membuat JS referensi aliran sehingga dapat diteruskan ke .NET, di mana streamReference
adalah ArrayBuffer
, , Blob
atau array apa pun yang di ketik, seperti Uint8Array
atau Float32Array
, yang digunakan untuk membuat JS referensi aliran.
Memanggil metode .NET instans
Untuk memanggil metode .NET instans dari JavaScript (JS):
Teruskan instans .NET dengan merujuk ke JS dengan membungkus instans dalam DotNetObjectReference dan memanggilnya Create .
Panggil metode instans .NET dari menggunakan (disarankan) atau
invokeMethod
(hanya komponen sisi klien) dari yang diteruskan DotNetObjectReference.invokeMethodAsync
JS Berikan pengidentifikasi metode .NET instans dan argumen apa pun. Instans .NET juga dapat diteruskan sebagai argumen saat memanggil metode .NET lainnya dari JS.Dalam contoh berikut:
dotNetHelper
adalah DotNetObjectReference.- Tempat
{.NET METHOD ID}
penampung adalah pengidentifikasi metode .NET. - Tempat
{ARGUMENTS}
penampung adalah argumen opsional yang dipisahkan koma untuk diteruskan ke metode , yang masing-masing harus dapat diserialisasikan JSON.
dotNetHelper.invokeMethodAsync('{.NET METHOD ID}', {ARGUMENTS});
Catatan
invokeMethodAsync
daninvokeMethod
tidak menerima parameter nama rakitan saat memanggil metode instans.invokeMethodAsync
mengembalikan yang JSPromise
mewakili hasil operasi.invokeMethod
(hanya komponen sisi klien) mengembalikan hasil operasi.Penting
Untuk komponen sisi server, kami merekomendasikan fungsi asinkron (
invokeMethodAsync
) melalui versi sinkron (invokeMethod
).Buang DotNetObjectReference.
Bagian berikut dari artikel ini menunjukkan berbagai pendekatan untuk memanggil metode .NET instans:
Hindari pemangkasan metode .NET yang dapat dipanggil JavaScript
Bagian ini berlaku untuk aplikasi sisi klien dengan kompilasi ahead-of-time (AOT) dan runtime relinking diaktifkan.
Beberapa contoh di bagian berikut didasarkan pada pendekatan instans kelas, di mana metode .NET yang dapat dipanggil JavaScript yang ditandai dengan [JSInvokable]
atribut adalah anggota kelas yang bukan Razor komponen. Ketika metode .NET tersebut terletak di komponen Razor , metode tersebut dilindungi dari runtime relinking/pemangkasan. Untuk melindungi metode .NET dari pemangkasan Razor di luar komponen, terapkan metode dengan DynamicDependency
atribut pada konstruktor kelas, seperti yang ditunjukkan contoh berikut:
using System.Diagnostics.CodeAnalysis;
using Microsoft.JSInterop;
public class ExampleClass {
[DynamicDependency(nameof(ExampleJSInvokableMethod))]
public ExampleClass()
{
}
[JSInvokable]
public string ExampleJSInvokableMethod()
{
...
}
}
Untuk informasi selengkapnya, lihat Menyiapkan pustaka .NET untuk pemangkasan: DynamicDependency.
Meneruskan DotNetObjectReference
ke fungsi JavaScript individual
Contoh di bagian ini menunjukkan cara meneruskan DotNetObjectReference ke fungsi JavaScript (JS) individual.
Fungsi berikut sayHello1
JS menerima DotNetObjectReference panggilan invokeMethodAsync
dan untuk memanggil GetHelloMessage
metode .NET komponen:
<script>
window.sayHello1 = (dotNetHelper) => {
return dotNetHelper.invokeMethodAsync('GetHelloMessage');
};
</script>
Catatan
Untuk panduan umum tentang JS lokasi dan rekomendasi kami untuk aplikasi produksi, lihat Lokasi JavaScript di aplikasi ASP.NET CoreBlazor.
Dalam contoh sebelumnya, nama dotNetHelper
variabel bersifat arbitrer dan dapat diubah ke nama pilihan apa pun.
Untuk komponen berikut:
- Komponen memiliki JSmetode .NET yang dapat dipanggil bernama
GetHelloMessage
. - Ketika tombol
Trigger .NET instance method
dipilih, fungsisayHello1
dipanggil JS dengan DotNetObjectReference. sayHello1
:GetHelloMessage
Memanggil dan menerima hasil pesan.- Mengembalikan hasil pesan ke metode panggilan
TriggerDotNetInstanceMethod
.
- Pesan yang dikembalikan dari
sayHello1
masukresult
ditampilkan kepada pengguna. - Untuk menghindari kebocoran memori dan mengizinkan pengumpulan sampah, referensi objek .NET yang dibuat oleh DotNetObjectReference dibuang dalam
Dispose
metode .
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();
}
}
Dalam contoh sebelumnya, nama dotNetHelper
variabel bersifat arbitrer dan dapat diubah ke nama pilihan apa pun.
Gunakan panduan berikut untuk meneruskan argumen ke metode instans:
Tambahkan parameter ke pemanggilan metode .NET. Dalam contoh berikut, nama diteruskan ke metode . Tambahkan parameter tambahan ke daftar sesuai kebutuhan.
<script>
window.sayHello2 = (dotNetHelper, name) => {
return dotNetHelper.invokeMethodAsync('GetHelloMessage', name);
};
</script>
Dalam contoh sebelumnya, nama dotNetHelper
variabel bersifat arbitrer dan dapat diubah ke nama pilihan apa pun.
Berikan daftar parameter ke metode .NET.
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();
}
}
Dalam contoh sebelumnya, nama dotNetHelper
variabel bersifat arbitrer dan dapat diubah ke nama pilihan apa pun.
Meneruskan DotNetObjectReference
ke kelas dengan beberapa fungsi JavaScript
Contoh di bagian ini menunjukkan cara meneruskan DotNetObjectReference ke kelas JavaScript (JS) dengan beberapa fungsi.
Buat dan teruskan DotNetObjectReference OnAfterRenderAsync
dari metode siklus hidup ke JS kelas untuk digunakan beberapa fungsi. Pastikan bahwa kode .NET membuang DotNetObjectReference, seperti yang ditunjukkan contoh berikut.
Dalam komponen berikut, tombol Trigger JS function
memanggil fungsi dengan mengaturonclick
JSproperti, bukan Blazor@onclick
atribut direktifJS.
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();
}
}
Dalam contoh sebelumnya:
JS
adalah instans yang disuntikkan IJSRuntime . IJSRuntime terdaftar oleh Blazor kerangka kerja.- Nama
dotNetHelper
variabel bersifat arbitrer dan dapat diubah ke nama pilihan apa pun. - Komponen harus secara eksplisit membuang untuk mengizinkan pengumpulan DotNetObjectReference sampah dan mencegah kebocoran memori.
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);
}
Dalam contoh sebelumnya, nama dotNetHelper
variabel bersifat arbitrer dan dapat diubah ke nama pilihan apa pun.
@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();
}
}
Dalam contoh sebelumnya:
JS
adalah instans yang disuntikkan IJSRuntime . IJSRuntime terdaftar oleh Blazor kerangka kerja.- Nama
dotNetHelper
variabel bersifat arbitrer dan dapat diubah ke nama pilihan apa pun. - Komponen harus secara eksplisit membuang untuk mengizinkan pengumpulan DotNetObjectReference sampah dan mencegah kebocoran memori.
<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>
Dalam contoh sebelumnya:
- Kelas
GreetingHelpers
ditambahkan kewindow
objek untuk menentukan kelas secara global, yang memungkinkan Blazor untuk menemukan kelas untuk JS interop. - Nama
dotNetHelper
variabel bersifat arbitrer dan dapat diubah ke nama pilihan apa pun.
Catatan
Untuk panduan umum tentang JS lokasi dan rekomendasi kami untuk aplikasi produksi, lihat Lokasi JavaScript di aplikasi ASP.NET CoreBlazor.
Memanggil metode kelas generik .NET
Fungsi JavaScript (JS) dapat memanggil metode kelas generik .NET, di mana JS fungsi memanggil metode .NET dari kelas generik.
Di kelas jenis generik berikut (GenericType<TValue>
):
- Kelas memiliki parameter jenis tunggal (
TValue
) dengan satu properti generikValue
. - Kelas ini memiliki dua metode non-generik yang ditandai dengan
[JSInvokable]
atribut , masing-masing dengan parameter jenis generik bernamanewValue
:Update
secara sinkron memperbarui nilai dariValue
newValue
.UpdateAsync
secara asinkron memperbarui nilaiValue
darinewValue
setelah membuat tugas yang dapat ditunggu dengan Task.Yield yang secara asinkron menghasilkan kembali ke konteks saat ini ketika ditunggu.
- Masing-masing metode kelas menulis jenis
TValue
dan nilaiValue
ke konsol. Menulis ke konsol hanya untuk tujuan demonstrasi. Aplikasi produksi biasanya menghindari penulisan ke konsol demi pengelogan aplikasi. Untuk informasi selengkapnya, lihat ASP.NET Pengelogan dan Pengelogan Core Blazor di .NET Core dan ASP.NET Core.
Catatan
Buka jenis dan metode generik tidak menentukan jenis untuk tempat penampung jenis. Sebaliknya, jenis pasokan generik tertutup untuk semua tempat penampung jenis. Contoh di bagian ini menunjukkan generik tertutup, tetapi memanggil metode instans interop dengan generik terbuka didukung.JS Penggunaan generik terbuka tidak didukung untuk pemanggilan metode .NET statis, yang dijelaskan sebelumnya dalam artikel ini.
Untuk informasi lebih lanjut, baca artikel berikut:
- Kelas dan metode generik (dokumentasi C#)
- Kelas Generik (Panduan Pemrograman C#)
- Generik dalam dokumentasi .NET (.NET)
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}");
}
}
Dalam fungsi berikut invokeMethodsAsync
:
- Kelas dan
UpdateAsync
metode jenisUpdate
generik dipanggil dengan argumen yang mewakili string dan angka. - Komponen sisi klien mendukung panggilan metode .NET secara sinkron dengan
invokeMethod
.syncInterop
menerima nilai boolean yang menunjukkan apakah JS interop terjadi pada klien. KetikasyncInterop
adalahtrue
,invokeMethod
dipanggil dengan aman. Jika nilaisyncInterop
adalahfalse
, hanya fungsiinvokeMethodAsync
asinkron yang dipanggil karena JS interop dijalankan dalam komponen sisi server. - Untuk tujuan demonstrasi, DotNetObjectReference panggilan fungsi (
invokeMethod
atauinvokeMethodAsync
), metode .NET yang disebut (Update
atauUpdateAsync
), dan argumen ditulis ke konsol. Argumen menggunakan nomor acak untuk mengizinkan pencocokan JS panggilan fungsi ke pemanggilan metode .NET (juga ditulis ke konsol di sisi .NET). Kode produksi biasanya tidak menulis ke konsol, baik di klien atau server. Aplikasi produksi biasanya mengandalkan pengelogan aplikasi. Untuk informasi selengkapnya, lihat ASP.NET Pengelogan dan Pengelogan Core Blazor di .NET Core dan 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>
Catatan
Untuk panduan umum tentang JS lokasi dan rekomendasi kami untuk aplikasi produksi, lihat Lokasi JavaScript di aplikasi ASP.NET CoreBlazor.
Dalam komponen GenericsExample
berikut:
- Fungsi JS
invokeMethodsAsync
ini dipanggil saat tombolInvoke Interop
dipilih. - Sepasang jenis DotNetObjectReference dibuat dan diteruskan ke JS fungsi untuk instans
GenericType
sebagaistring
danint
.
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();
}
}
Dalam contoh sebelumnya, JS
adalah instans yang disuntikkan IJSRuntime . IJSRuntime terdaftar oleh Blazor kerangka kerja.
Berikut ini menunjukkan output umum dari contoh sebelumnya saat tombol Invoke Interop
dipilih dalam komponen sisi klien:
JS: invokeMethodAsync:Update('string 37802')
.NET: Pembaruan: GenericType<System.String>: string 37802
JS: invokeMethodAsync:UpdateAsync('string 53051')
JS: invokeMethod:Update('string 26784')
.NET: Pembaruan: GenericType<System.String>: string 26784
JS: invokeMethodAsync:Update(14107)
.NET: Pembaruan: GenericType<System.Int32>: 14107
JS: invokeMethodAsync:UpdateAsync(48995)
JS: invokeMethod:Update(12872)
.NET: Pembaruan: GenericType<System.Int32>: 12872
.NET: UpdateAsync: GenericType<System.String>: string 53051
.NET: UpdateAsync: GenericType<System.Int32>: 48995
Jika contoh sebelumnya diimplementasikan dalam komponen sisi server, panggilan sinkron dengan invokeMethod
dihindari. Untuk komponen sisi server, kami merekomendasikan fungsi asinkron (invokeMethodAsync
) melalui versi sinkron (invokeMethod
).
Output umum komponen sisi server:
JS: invokeMethodAsync:Update('string 34809')
.NET: Pembaruan: GenericType<System.String>: string 34809
JS: invokeMethodAsync:UpdateAsync('string 93059')
JS: invokeMethodAsync:Update(41997)
.NET: Pembaruan: GenericType<System.Int32>: 41997
JS: invokeMethodAsync:UpdateAsync(24652)
.NET: UpdateAsync: GenericType<System.String>: string 93059
.NET: UpdateAsync: GenericType<System.Int32>: 24652
Contoh output sebelumnya menunjukkan bahwa metode asinkron dijalankan dan diselesaikan dalam urutan arbitrer tergantung pada beberapa faktor, termasuk penjadwalan utas dan kecepatan eksekusi metode. Tidak dimungkinkan untuk memprediksi urutan penyelesaian panggilan metode asinkron dengan andal.
Contoh instans kelas
Fungsi berikut sayHello1
JS :
GetHelloMessage
Memanggil metode .NET pada yang diteruskan DotNetObjectReference.- Mengembalikan pesan dari
GetHelloMessage
ke pemanggilsayHello1
.
<script>
window.sayHello1 = (dotNetHelper) => {
return dotNetHelper.invokeMethodAsync('GetHelloMessage');
};
</script>
Catatan
Untuk panduan umum tentang JS lokasi dan rekomendasi kami untuk aplikasi produksi, lihat Lokasi JavaScript di aplikasi ASP.NET CoreBlazor.
Dalam contoh sebelumnya, nama dotNetHelper
variabel bersifat arbitrer dan dapat diubah ke nama pilihan apa pun.
Kelas berikut HelloHelper
memiliki JSmetode .NET yang dapat dipanggil bernama GetHelloMessage
. Saat HelloHelper
dibuat, nama dalam Name
properti digunakan untuk mengembalikan pesan dari GetHelloMessage
.
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}!";
}
Metode CallHelloHelperGetHelloMessage
di kelas berikut JsInteropClasses3
memanggil fungsi sayHello1
dengan instans JS baru .HelloHelper
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);
}
}
Untuk menghindari kebocoran memori dan mengizinkan pengumpulan sampah, referensi objek .NET yang dibuat oleh DotNetObjectReference dibuang ketika referensi objek keluar dari cakupan dengan using var
sintaksis.
Ketika tombol Trigger .NET instance method
dipilih dalam komponen berikut, JsInteropClasses3.CallHelloHelperGetHelloMessage
dipanggil dengan nilai 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);
}
}
}
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);
}
}
Gambar berikut menunjukkan komponen yang dirender dengan nama Amy Pond
di Name
bidang . Setelah tombol dipilih, Hello, Amy Pond!
ditampilkan di UI:
Pola sebelumnya yang ditunjukkan di JsInteropClasses3
kelas juga dapat diimplementasikan sepenuhnya dalam komponen.
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);
}
}
Untuk menghindari kebocoran memori dan mengizinkan pengumpulan sampah, referensi objek .NET yang dibuat oleh DotNetObjectReference dibuang ketika referensi objek keluar dari cakupan dengan using var
sintaksis.
Output yang ditampilkan oleh komponen adalah Hello, Amy Pond!
ketika nama Amy Pond
disediakan di name
bidang .
Dalam komponen sebelumnya, referensi objek .NET dibuang. Jika kelas atau komponen tidak membuang DotNetObjectReference, buang dari klien dengan memanggil dispose
yang diteruskan DotNetObjectReference:
window.{JS FUNCTION NAME} = (dotNetHelper) => {
dotNetHelper.invokeMethodAsync('{.NET METHOD ID}');
dotNetHelper.dispose();
}
Dalam contoh sebelumnya:
- Tempat
{JS FUNCTION NAME}
penampung adalah JS nama fungsi. - Nama
dotNetHelper
variabel bersifat arbitrer dan dapat diubah ke nama pilihan apa pun. - Tempat
{.NET METHOD ID}
penampung adalah pengidentifikasi metode .NET.
Kelas pembantu metode .NET instans komponen
Kelas pembantu dapat memanggil metode instans .NET sebagai Action. Kelas pembantu berguna dalam skenario saat menggunakan metode .NET statis tidak berlaku:
- Ketika beberapa komponen dengan jenis yang sama dirender pada halaman yang sama.
- Di aplikasi sisi server dengan beberapa pengguna secara bersamaan menggunakan komponen yang sama.
Dalam contoh berikut:
- Komponen berisi beberapa
ListItem1
komponen. - Setiap
ListItem1
komponen terdiri dari pesan dan tombol. ListItem1
Ketika tombol komponen dipilih,ListItem1
metode ituUpdateMessage
mengubah teks item daftar dan menyembunyikan tombol.
Kelas berikut MessageUpdateInvokeHelper
mempertahankan JSmetode .NET yang dapat dipanggil, UpdateMessageCaller
, untuk memanggil Action yang ditentukan saat kelas dibuat.
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();
}
}
Fungsi UpdateMessageCaller
berikut updateMessageCaller
JS memanggil metode .NET.
<script>
window.updateMessageCaller = (dotNetHelper) => {
dotNetHelper.invokeMethodAsync('UpdateMessageCaller');
dotNetHelper.dispose();
}
</script>
Catatan
Untuk panduan umum tentang JS lokasi dan rekomendasi kami untuk aplikasi produksi, lihat Lokasi JavaScript di aplikasi ASP.NET CoreBlazor.
Dalam contoh sebelumnya, nama dotNetHelper
variabel bersifat arbitrer dan dapat diubah ke nama pilihan apa pun.
Komponen berikut ListItem1
adalah komponen bersama yang dapat digunakan berapa kali dalam komponen induk dan membuat item daftar (<li>...</li>
) untuk daftar HTML (<ul>...</ul>
atau <ol>...</ol>
). Setiap ListItem1
instans komponen menetapkan instans MessageUpdateInvokeHelper
dengan set Action ke metodenya UpdateMessage
.
ListItem1
Saat tombol komponen InteropCall
dipilih, updateMessageCaller
dipanggil dengan dibuat DotNetObjectReference untuk MessageUpdateInvokeHelper
instans. Ini memungkinkan kerangka kerja untuk memanggil UpdateMessageCaller
ListItem1
instans tersebut MessageUpdateInvokeHelper
. Yang diteruskan DotNetObjectReference dibuang di JS (dotNetHelper.dispose()
).
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
dipanggil untuk memperbarui UI saat message
diatur dalam UpdateMessage
. Jika StateHasChanged
tidak dipanggil, Blazor tidak memiliki cara untuk mengetahui bahwa UI harus diperbarui ketika Action dipanggil.
Komponen induk berikut mencakup empat item daftar, setiap instans ListItem1
komponen.
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>
Gambar berikut menunjukkan komponen induk yang dirender setelah tombol kedua InteropCall
dipilih:
- Komponen kedua
ListItem1
telah menampilkanUpdateMessage Called!
pesan. - Tombol
InteropCall
untuk komponen keduaListItem1
tidak terlihat karena properti CSSdisplay
tombol diatur kenone
.
Metode .NET instans komponen yang dipanggil dari DotNetObjectReference
ditetapkan ke properti elemen
Penugasan DotNetObjectReference ke properti elemen HTML memungkinkan panggilan metode .NET pada instans komponen:
- Referensi elemen diambil (ElementReference).
- Dalam metode komponen
OnAfterRender{Async}
, fungsi JavaScript (JS) dipanggil dengan referensi elemen dan instans komponen sebagai DotNetObjectReference. Fungsi JS melampirkan DotNetObjectReference ke elemen dalam properti. - Ketika peristiwa elemen dipanggil di JS (misalnya,
onclick
), elemen yang dilampirkan DotNetObjectReference digunakan untuk memanggil metode .NET.
Mirip dengan pendekatan yang dijelaskan di bagian Kelas pembantu metode .NET instans komponen, pendekatan ini berguna dalam skenario di mana menggunakan metode .NET statis tidak berlaku:
- Ketika beberapa komponen dengan jenis yang sama dirender pada halaman yang sama.
- Di aplikasi sisi server dengan beberapa pengguna secara bersamaan menggunakan komponen yang sama.
- Metode .NET dipanggil dari JS peristiwa (misalnya,
onclick
), bukan dari Blazor peristiwa (misalnya,@onclick
).
Dalam contoh berikut:
- Komponen berisi beberapa
ListItem2
komponen, yang merupakan komponen bersama. - Setiap
ListItem2
komponen terdiri dari pesan<span>
item daftar dan satu detik<span>
dengan properti CSS diaturdisplay
keinline-block
untuk ditampilkan. ListItem2
Saat item daftar komponen dipilih,ListItem2
metode ituUpdateMessage
mengubah teks item daftar di item pertama<span>
dan menyembunyikan yang kedua<span>
dengan mengatur propertinyadisplay
kenone
.
Fungsi berikut assignDotNetHelper
JS menetapkan DotNetObjectReference ke elemen dalam properti bernama dotNetHelper
. Fungsi berikut interopCall
JS menggunakan DotNetObjectReference untuk elemen yang diteruskan untuk memanggil metode .NET bernama 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>
Catatan
Untuk panduan umum tentang JS lokasi dan rekomendasi kami untuk aplikasi produksi, lihat Lokasi JavaScript di aplikasi ASP.NET CoreBlazor.
Dalam contoh sebelumnya, nama dotNetHelper
variabel bersifat arbitrer dan dapat diubah ke nama pilihan apa pun.
Komponen berikut ListItem2
adalah komponen bersama yang dapat digunakan berapa kali dalam komponen induk dan membuat item daftar (<li>...</li>
) untuk daftar HTML (<ul>...</ul>
atau <ol>...</ol>
).
Setiap ListItem2
instansJS assignDotNetHelper
komponen memanggil fungsi dengan OnAfterRenderAsync
referensi elemen (elemen pertama <span>
dari item daftar) dan instans komponen sebagai DotNetObjectReference.
ListItem2
Ketika pesan <span>
komponen dipilih, interopCall
dipanggil meneruskan <span>
elemen sebagai parameter (this
), yang memanggil UpdateMessage
metode .NET. Dalam UpdateMessage
, StateHasChanged
dipanggil untuk memperbarui UI saat message
diatur dan display
properti kedua <span>
diperbarui. Jika StateHasChanged
tidak dipanggil, Blazor tidak memiliki cara untuk mengetahui bahwa UI harus diperbarui ketika metode dipanggil.
dibuang DotNetObjectReference ketika komponen dibuang.
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();
}
Komponen induk berikut mencakup empat item daftar, setiap instans ListItem2
komponen.
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>
Interop sinkron JS dalam komponen sisi klien
Bagian ini hanya berlaku untuk komponen sisi klien.
JS panggilan interop tidak sinkron, terlepas dari apakah kode yang disebut sinkron atau asinkron. Panggilan bersifat asinkron untuk memastikan bahwa komponen kompatibel di seluruh mode render sisi server dan sisi klien. Di server, semua JS panggilan interop harus asinkron karena dikirim melalui koneksi jaringan.
Jika Anda tahu dengan pasti bahwa komponen Anda hanya berjalan di WebAssembly, Anda dapat memilih untuk melakukan panggilan interop sinkron JS . Ini memiliki overhead yang sedikit lebih sedikit daripada melakukan panggilan asinkron dan dapat mengakibatkan lebih sedikit siklus render karena tidak ada status menengah saat menunggu hasil.
Untuk melakukan panggilan sinkron dari JavaScript ke .NET dalam komponen sisi klien, gunakan DotNet.invokeMethod
alih-alih DotNet.invokeMethodAsync
.
Panggilan sinkron berfungsi jika:
Lokasi JavaScript
Muat kode JavaScript (JS) menggunakan salah satu pendekatan yang dijelaskan oleh artikel tentang lokasi JavaScript:
Menggunakan JS modul untuk memuat JS dijelaskan dalam artikel ini di bagian isolasi JavaScript di modul JavaScript.
Peringatan
Hanya tempatkan <script>
tag dalam file komponen (.razor
) jika komponen dijamin untuk mengadopsi penyajian sisi server statis (SSR statis) karena <script>
tag tidak dapat diperbarui secara dinamis.
Peringatan
Jangan menempatkan <script>
tag dalam file komponen (.razor
) karena <script>
tag tidak dapat diperbarui secara dinamis.
Isolasi JavaScript dalam modul JavaScript
Blazor mengaktifkan isolasi JavaScript (JS) dalam modul JavaScript standar (spesifikasi ECMAScript). Pemuatan modul JavaScript berfungsi dengan cara Blazor yang sama seperti halnya untuk jenis aplikasi web lainnya, dan Anda bebas menyesuaikan bagaimana modul ditentukan di aplikasi Anda. Untuk panduan tentang cara menggunakan modul JavaScript, lihat MDN Web Docs: Modul JavaScript.
JS isolasi memberikan manfaat berikut:
- JS yang diimpor tidak lagi mencemari namespace global.
- Konsumen pustaka dan komponen tidak perlu mengimpor JS terkait.
Untuk informasi lebih lanjut, lihat Memanggil fungsi JavaScript dari metode .NET di Blazor ASP.NET Core.
Impor dinamis dengan import()
operator didukung dengan ASP.NET Core dan Blazor:
if ({CONDITION}) import("/additionalModule.js");
Dalam contoh sebelumnya, {CONDITION}
tempat penampung mewakili pemeriksaan bersyariah untuk menentukan apakah modul harus dimuat.
Untuk kompatibilitas browser, lihat Dapatkah saya menggunakan: modul JavaScript: impor dinamis.
Hindari referensi objek melingkar
Objek yang berisi referensi melingkar tidak dapat diserialisasikan pada klien untuk:
- Panggilan metode .NET.
- Metode JavaScript memanggil dari C# ketika jenis pengembalian memiliki referensi melingkar.
Dukungan array byte
Blazor mendukung interop JavaScriptJS () array byte yang dioptimalkan yang menghindari pengodean/pendekodean array byte ke Base64. Contoh berikut menggunakan JS interop untuk meneruskan array byte ke .NET.
sendByteArray
JS Menyediakan fungsi. Fungsi ini disebut secara statis, yang mencakup parameter nama rakitan dalam invokeMethodAsync
panggilan, dengan tombol dalam komponen dan tidak mengembalikan nilai:
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>
Catatan
Untuk panduan umum tentang JS lokasi dan rekomendasi kami untuk aplikasi produksi, lihat Lokasi JavaScript di aplikasi ASP.NET CoreBlazor.
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));
}
}
Untuk informasi tentang menggunakan array byte saat memanggil JavaScript dari .NET, lihat Memanggil fungsi JavaScript dari metode .NET di ASP.NET Core Blazor.
Streaming dari JavaScript ke .NET
Blazor mendukung streaming data langsung dari JavaScript ke .NET. Aliran diminta menggunakan Microsoft.JSInterop.IJSStreamReference
antarmuka .
Microsoft.JSInterop.IJSStreamReference.OpenReadStreamAsync
Stream mengembalikan dan menggunakan parameter berikut:
maxAllowedSize
: Jumlah maksimum byte yang diizinkan untuk operasi baca dari JavaScript, yang defaultnya adalah 512.000 byte jika tidak ditentukan.cancellationToken
: A CancellationToken untuk membatalkan bacaan.
Di JavaScript:
function streamToDotNet() {
return new Uint8Array(10000000);
}
Dalam kode C#:
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);
Dalam contoh sebelumnya:
JS
adalah instans yang disuntikkan IJSRuntime . IJSRuntime terdaftar oleh Blazor kerangka kerja.dataReferenceStream
ditulis ke disk (file.txt
) di jalur folder sementara pengguna saat ini (GetTempPath).
Memanggil fungsi JavaScript dari metode .NET di ASP.NET Core Blazor mencakup operasi terbalik, streaming dari .NET ke JavaScript menggunakan DotNetStreamReference.
unggahan file ASP.NET Core Blazor mencakup cara mengunggah file di Blazor. Untuk contoh formulir yang mengalirkan <textarea>
data dalam komponen sisi server, lihat Memecahkan masalah formulir ASP.NET CoreBlazor.
Interop JavaScript [JSImport]
/[JSExport]
Bagian ini berlaku untuk komponen sisi klien.
Sebagai alternatif untuk berinteraksi dengan JavaScript (JS) di komponen sisi klien menggunakan JS Blazormekanisme interop berdasarkan IJSRuntime antarmuka,/JS[JSImport]
[JSExport]
API interop tersedia untuk aplikasi yang menargetkan .NET 7 atau yang lebih baru.
Untuk informasi selengkapnya, lihat Interop JavaScript JSImport/JSExport dengan ASP.NET Core Blazor.
Pembuangan referensi objek interop JavaScript
Contoh di seluruh artikel interop JavaScript (JS) menunjukkan pola pembuangan objek umum:
Saat memanggil .NET dari JS, seperti yang dijelaskan dalam artikel ini, buang yang dibuat DotNetObjectReference baik dari .NET atau dari JS untuk menghindari kebocoran memori .NET.
Saat memanggil JS dari .NET, seperti yang dijelaskan dalam Memanggil fungsi JavaScript dari metode .NET di ASP.NET Core Blazor, buang apa pun yang dibuatIJSInProcessObjectReference//
JSObjectReference
IJSObjectReferencebaik dari .NET atau dari JS untuk menghindari kebocoran JS memori.
JS referensi objek interop diimplementasikan sebagai peta yang dikunci oleh pengidentifikasi di sisi JS panggilan interop yang membuat referensi. Ketika pembuangan objek dimulai dari .NET atau JS sisi, Blazor menghapus entri dari peta, dan objek dapat menjadi sampah yang dikumpulkan selama tidak ada referensi kuat lainnya ke objek yang ada.
Minimal, selalu buang objek yang dibuat di sisi .NET untuk menghindari kebocoran memori terkelola .NET.
Tugas pembersihan DOM selama pembuangan komponen
Untuk informasi selengkapnya, lihat ASP.NET Blazor interoperabilitas Core JavaScript (JS interop).
Panggilan interop JavaScript tanpa sirkuit
Untuk informasi selengkapnya, lihat ASP.NET Blazor interoperabilitas Core JavaScript (JS interop).
Sumber Daya Tambahan:
- Memanggil fungsi JavaScript dari metode .NET di Blazor ASP.NET Core
InteropComponent.razor
contoh (dotnet/AspNetCore
cabang repositorimain
GitHub): Cabangmain
mewakili pengembangan unit produk saat ini untuk rilis ASP.NET Core berikutnya. Untuk memilih cabang untuk rilis yang berbeda (misalnya,release/{VERSION}
, di mana{VERSION}
tempat penampung adalah versi rilis), gunakan daftar dropdown Beralih cabang atau tag untuk memilih cabang. Untuk cabang yang sudah tidak ada lagi, gunakan tab Tag untuk menemukan API (misalnya,v7.0.0
).- Interaksi dengan DOM
- Blazorsampel repositori GitHub () (
dotnet/blazor-samples
cara mengunduh) - Menangani kesalahan di aplikasi ASP.NET Core Blazor (bagian interop JavaScript)
- Mitigasi ancaman: Metode .NET yang dipanggil dari browser
ASP.NET Core