Bagikan melalui


Interoperabilitas JavaScript Blazor ASP.NET Core (interop JS)

Catatan

Ini bukan versi terbaru dari artikel ini. Untuk rilis saat ini, lihat versi .NET 8 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 8 dari artikel ini.

Aplikasi Blazor dapat menjalankan fungsi JavaScript (JS) dari metode .NET dan metode .NET dari fungsi JS. Skenario ini disebut interoperabilitas JavaScript (interop JS).

Panduan interop JS lebih lanjut disediakan dalam artikel berikut:

Catatan

API interop JavaScript [JSImport]/[JSExport] tersedia untuk komponen sisi klien di ASP.NET Core di .NET 7 atau yang lebih baru.

Untuk informasi selengkapnya, lihat Interop JavaScript JSImport/JSExport dengan ASP.NET Core Blazor.

Pemadatan untuk komponen server interaktif dengan data yang tidak tepercaya

Dengan kompresi, yang diaktifkan secara default, hindari membuat komponen sisi server interaktif yang aman (diautentikasi/diotorisasi) yang merender data dari sumber yang tidak tepercaya. Sumber yang tidak tepercaya termasuk parameter rute, string kueri, data dari JS interop, dan sumber data lain yang dapat dikontrol pengguna pihak ketiga (database, layanan eksternal). Untuk informasi selengkapnya, lihat panduan inti BlazorSignalR ASP.NET dan panduan mitigasi ancaman untuk penyajian sisi server interaktif ASP.NET CoreBlazor.

Paket abstraksi dan fitur interop JavaScript

Paket @microsoft/dotnet-js-interop (npmjs.com) (Microsoft.JSInterop paket NuGet) menyediakan abstraksi dan fitur untuk interop antara kode .NET dan JavaScript (JS). Sumber referensi tersedia di dotnet/aspnetcore repositori GitHub (/src/JSInterop folder). Untuk informasi selengkapnya, lihat file repositori README.md GitHub.

Catatan

Tautan dokumentasi ke sumber referensi .NET biasanya memuat cabang default repositori, yang mewakili pengembangan saat ini untuk rilis .NET berikutnya. Untuk memilih tag rilis tertentu, gunakan daftar dropdown Beralih cabang atau tag. Untuk informasi lebih lanjut, lihat Cara memilih tag versi kode sumber ASP.NET Core (dotnet/AspNetCore.Docs #26205).

Sumber daya tambahan untuk menulis JS skrip interop di TypeScript:

Interaksi dengan DOM

Hanya bermutasi DOM dengan JavaScript (JS) saat objek tidak berinteraksi dengan Blazor. Blazor mempertahankan representasi DOM dan berinteraksi langsung dengan objek DOM. Jika elemen yang dirender oleh Blazor dimodifikasi secara eksternal menggunakan JS secara langsung atau melalui Interop JS, DOM mungkin tidak lagi cocok dengan representasi internal Blazor, yang dapat mengakibatkan perilaku yang tidak ditentukan. Perilaku yang tidak ditentukan mungkin hanya dapat mengganggu presentasi elemen atau fungsinya, tetapi juga dapat menimbulkan risiko keamanan ke aplikasi atau server.

Panduan ini tidak hanya berlaku untuk kode interop JS Anda sendiri, tetapi juga untuk setiap pustaka JS yang digunakan aplikasi, termasuk apa pun yang disediakan oleh kerangka kerja pihak ketiga, seperti Bootstrap JS dan jQuery.

Dalam beberapa contoh dokumentasi, JS interop digunakan untuk mengubah elemen semata-mata untuk tujuan demonstrasi sebagai bagian dari contoh. Dalam kasus tersebut, peringatan muncul di teks.

Untuk informasi lebih lanjut, lihat Memanggil fungsi JavaScript dari metode .NET di Blazor ASP.NET Core.

Kelas JavaScript dengan bidang fungsi jenis

Kelas JavaScript dengan bidang fungsi jenis tidak didukung oleh BlazorJS interop. Gunakan fungsi Javascript di kelas.

Tidak didukung: GreetingHelpers.sayHello di kelas berikut sebagai bidang fungsi jenis tidak ditemukan oleh Blazorinterop 's JS dan tidak dapat dijalankan dari kode C#:

export class GreetingHelpers {
  sayHello = function() {
    ...
  }
}

Didukung: GreetingHelpers.sayHello di kelas berikut sebagai fungsi didukung:

export class GreetingHelpers {
  sayHello() {
    ...
  }
}

Fungsi panah juga didukung:

export class GreetingHelpers {
  sayHello = () => {
    ...
  }
}

Hindari penanganan aktivitas sebaris

Fungsi JavaScript dapat dipanggil langsung dari penanganan aktivitas sebaris. Dalam contoh berikut, alertUser adalah fungsi JavaScript yang dipanggil saat tombol dipilih oleh pengguna:

<button onclick="alertUser">Click Me!</button>

Namun, penggunaan penanganan aktivitas sebaris adalah pilihan desain yang buruk untuk memanggil fungsi JavaScript:

Sebaiknya hindari penanganan aktivitas sebaris demi pendekatan yang menetapkan handler di JavaScript dengan addEventListener, seperti yang ditunjukkan contoh berikut:

AlertUser.razor.js:

export function alertUser() {
  alert('The button was selected!');
}

export function addHandlers() {
  const btn = document.getElementById("btn");
  btn.addEventListener("click", alertUser);
}

AlertUser.razor:

@page "/alert-user"
@implements IAsyncDisposable
@inject IJSRuntime JS

<h1>Alert User</h1>

<p>
    <button id="btn">Click Me!</button>
</p>

@code {
    private IJSObjectReference? module;

    protected async override Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            module = await JS.InvokeAsync<IJSObjectReference>("import",
                "./Components/Pages/AlertUser.razor.js");

            await module.InvokeVoidAsync("addHandlers");
        }
    }

    async ValueTask IAsyncDisposable.DisposeAsync()
    {
        if (module is not null)
        {
            await module.DisposeAsync();
        }
    }
}

Untuk informasi selengkapnya, lihat sumber daya berikut:

Panggilan JavaScript asinkron

JS panggilan interop tidak sinkron, terlepas dari apakah kode yang disebut sinkron atau asinkron. Panggilan bersifat asinkron untuk memastikan bahwa komponen kompatibel di seluruh model penyajian sisi server dan sisi klien. Saat mengadopsi penyajian sisi server, JS panggilan interop harus asinkron karena dikirim melalui koneksi jaringan. Untuk aplikasi yang secara eksklusif mengadopsi penyajian sisi klien, panggilan interop sinkron JS didukung.

Serialisasi objek

Blazor menggunakan System.Text.Json untuk serialisasi dengan persyaratan dan perilaku default berikut:

  • Jenis harus memiliki konstruktor default, get/set pengakses harus publik, dan bidang tidak pernah diserialisasi.
  • Serialisasi default global tidak dapat disesuaikan untuk menghindari kerusakan pustaka komponen yang ada, berdampak pada performa dan keamanan, serta pengurangan keandalan.
  • Serialisasi nama anggota .NET menghasilkan nama kunci JSON huruf kecil.
  • JSON dideserialisasi sebagai JsonElement instans C#, yang mengizinkan casing campuran. Transmisi internal untuk penugasan ke properti model C# berfungsi seperti yang diharapkan terlepas dari perbedaan kasus apa pun antara nama kunci JSON dan nama properti C#.
  • Jenis kerangka kerja yang kompleks, seperti KeyValuePair, mungkin dipangkas oleh Pemangkas IL pada publikasi dan tidak ada untuk JS interop. Sebaiknya buat jenis kustom untuk jenis yang dipangkas IL Trimmer.
  • Blazorselalu bergantung pada refleksi untuk serialisasi JSON, termasuk saat menggunakan pembuatan sumber C#. Pengaturan JsonSerializerIsReflectionEnabledByDefault ke false dalam file proyek aplikasi menghasilkan kesalahan saat serialisasi dicoba.

API JsonConverter tersedia untuk serialisasi kustom. Properti dapat dianotasi dengan atribut [JsonConverter] guna menggantikan serialisasi default untuk tipe data yang ada.

Untuk informasi lebih lanjut, lihat sumber daya berikut ini dalam dokumentasi .NET:

Blazor mendukung interop JS array byte yang dioptimalkan yang menghindari pengodean/pendekodean array byte ke Base64. Aplikasi dapat menerapkan serialisasi kustom dan meneruskan byte yang dihasilkan. Untuk informasi lebih lanjut, lihat Memanggil fungsi JavaScript dari metode .NET di Blazor ASP.NET Core.

Blazor mendukung interop JS unmarshalled saat volume objek .NET yang tinggi diserialisasikan dengan cepat atau saat objek .NET besar atau saat banyak objek .NET harus diserialisasi. Untuk informasi lebih lanjut, lihat Memanggil fungsi JavaScript dari metode .NET di Blazor ASP.NET Core.

Tugas pembersihan DOM selama pembuangan komponen

Jangan jalankan JS kode interop untuk tugas pembersihan DOM selama pembuangan komponen. Sebagai gantinya MutationObserver , gunakan pola di JavaScript (JS) pada klien karena alasan berikut:

  • Komponen mungkin telah dihapus dari DOM pada saat kode pembersihan Anda dijalankan di Dispose{Async}.
  • Selama penyajian sisi server, perender Blazor mungkin telah dibuang oleh kerangka kerja pada saat kode pembersihan Anda dijalankan di Dispose{Async}.

Pola ini MutationObserver memungkinkan Anda menjalankan fungsi saat elemen dihapus dari DOM.

Dalam contoh berikut, DOMCleanup komponen:

  • <div> Berisi dengan id .cleanupDiv Elemen <div> dihapus dari DOM bersama dengan rest markup DOM komponen saat komponen dihapus dari DOM.
  • DOMCleanupJS Memuat kelas dari DOMCleanup.razor.js file dan memanggil fungsinya createObserver untuk menyiapkan MutationObserver panggilan balik. Tugas-tugas ini dicapai dalam OnAfterRenderAsync metode siklus hidup.

DOMCleanup.razor:

@page "/dom-cleanup"
@implements IAsyncDisposable
@inject IJSRuntime JS

<h1>DOM Cleanup Example</h1>

<div id="cleanupDiv"></div>

@code {
    private IJSObjectReference? module;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            module = await JS.InvokeAsync<IJSObjectReference>(
                "import", "./Components/Pages/DOMCleanup.razor.js");

            await module.InvokeVoidAsync("DOMCleanup.createObserver");
        }
    }

    async ValueTask IAsyncDisposable.DisposeAsync()
    {
        if (module is not null)
        {
            await module.DisposeAsync();
        }
    }
}

Dalam contoh berikut, MutationObserver panggilan balik dijalankan setiap kali perubahan DOM terjadi. Jalankan kode pembersihan if Anda ketika pernyataan mengonfirmasi bahwa elemen target (cleanupDiv) dihapus (if (targetRemoved) { ... }). Penting untuk memutuskan dan menghapus untuk menghindari kebocoran MutationObserver memori setelah kode pembersihan Anda dijalankan.

DOMCleanup.razor.js ditempatkan berdampingan DOMCleanup dengan komponen sebelumnya:

export class DOMCleanup {
  static observer;

  static createObserver() {
    const target = document.querySelector('#cleanupDiv');

    this.observer = new MutationObserver(function (mutations) {
      const targetRemoved = mutations.some(function (mutation) {
        const nodes = Array.from(mutation.removedNodes);
        return nodes.indexOf(target) !== -1;
      });

      if (targetRemoved) {
        // Cleanup resources here
        // ...

        // Disconnect and delete MutationObserver
        this.observer && this.observer.disconnect();
        delete this.observer;
      }
    });

    this.observer.observe(target.parentNode, { childList: true });
  }
}

window.DOMCleanup = DOMCleanup;

Panggilan interop JavaScript tanpa sirkuit

Bagian ini hanya berlaku untuk aplikasi sisi server.

Panggilan interop JavaScript (JS) tidak dapat dikeluarkan setelah SignalR sirkuit terputus. Tanpa sirkuit selama pembuangan komponen atau di lain waktu bahwa sirkuit tidak ada, metode berikut memanggil gagal dan mencatat pesan bahwa sirkuit terputus sebagai JSDisconnectedException:

Untuk menghindari pengelogan JSDisconnectedException atau mencatat informasi kustom, tangkap pengecualian dalam pernyataan try-catch .

Untuk contoh pembuangan komponen berikut:

  • Komponen mengimplementasikan IAsyncDisposable.
  • objInstanceIJSObjectReferenceadalah .
  • JSDisconnectedException tertangkap dan tidak dicatat.
  • Secara opsional, Anda dapat mencatat informasi kustom dalam pernyataan pada catch tingkat log apa pun yang Anda inginkan. Contoh berikut tidak mencatat informasi kustom karena mengasumsikan pengembang tidak peduli tentang kapan atau di mana sirkuit terputus selama pembuangan komponen.
async ValueTask IAsyncDisposable.DisposeAsync()
{
    try
    {
        if (objInstance is not null)
        {
            await objInstance.DisposeAsync();
        }
    }
    catch (JSDisconnectedException)
    {
    }
}

Jika Anda harus membersihkan objek Anda sendiri JS atau menjalankan kode lain JS pada klien setelah sirkuit hilang, gunakan MutationObserver pola di JS pada klien. Pola ini MutationObserver memungkinkan Anda menjalankan fungsi saat elemen dihapus dari DOM.

Untuk informasi lebih lanjut, baca artikel berikut:

  • Menangani kesalahan di aplikasi ASP.NET CoreBlazor: Bagian interop JavaScript membahas penanganan kesalahan dalam JS skenario interop.
  • ASP.NET Siklus hidup komponen CoreRazor: Bagian pembuangan komponen dengan IDisposable dan IAsyncDisposable menjelaskan cara menerapkan pola pembuangan dalam Razor komponen.

File JavaScript yang di-cache

File JavaScript (JS) dan aset statis lainnya biasanya tidak disimpan dalam cache pada klien selama pengembangan di lingkungan Development. Selama pengembangan, permintaan aset statis menyertakan header Cache-Control dengan nilai no-cache atau max-age dengan nilai nol (0).

Selama produksi di Production lingkungan, file JS biasanya di-cache oleh klien.

Untuk menonaktifkan penembolokan sisi klien di browser, pengembang biasanya mengadopsi salah satu pendekatan berikut:

  • Nonaktifkan penembolokan saat konsol alat pengembang browser terbuka. Panduan dapat ditemukan dalam dokumentasi alat pengembang dari setiap pemeliharaan browser:
  • Lakukan refresh browser manual pada halaman web mana pun dari aplikasi Blazor untuk memuat ulang file JS dari server. HTTP Caching Middleware ASP.NET Core selalu menggunakan header Cache-Control tanpa cache yang valid yang dikirim oleh klien.

Untuk informasi selengkapnya, lihat:

Batas ukuran pada panggilan interop JavaScript

Bagian ini hanya berlaku untuk komponen interaktif di aplikasi sisi server. Untuk komponen sisi klien, kerangka kerja tidak memberlakukan batasan pada ukuran input dan output interop JavaScript (JS).

Untuk komponen interaktif di aplikasi sisi server, JS panggilan interop meneruskan data dari klien ke server berukuran SignalR terbatas pada ukuran pesan masuk maksimum yang diizinkan untuk metode hub, yang diberlakukan secara HubOptions.MaximumReceiveMessageSize default: 32 KB). JS ke pesan .NET SignalR lebih besar dari MaximumReceiveMessageSize melemparkan kesalahan. Kerangka kerja tidak memberlakukan batasan SignalR ukuran pesan dari hub ke klien. Untuk informasi selengkapnya tentang batas ukuran, pesan kesalahan, dan panduan tentang menangani batas ukuran pesan, lihat panduan ASP.NET CoreBlazorSignalR.

Menentukan tempat aplikasi berjalan

Jika relevan bagi aplikasi untuk mengetahui di mana kode berjalan untuk JS panggilan interop, gunakan OperatingSystem.IsBrowser untuk menentukan apakah komponen dijalankan dalam konteks browser di WebAssembly.