Menangani kesalahan di aplikasi 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 Blazor mengelola pengecualian yang tidak tertangani dan cara mengembangkan aplikasi yang mendeteksi dan menangani kesalahan.
Kesalahan terperinci selama pengembangan
Blazor Saat aplikasi tidak berfungsi dengan baik selama pengembangan, menerima informasi kesalahan terperinci dari aplikasi membantu pemecahan masalah dan memperbaiki masalah. Saat terjadi kesalahan, Blazor aplikasi menampilkan bilah kuning muda di bagian bawah layar:
- Selama pengembangan, bilah mengarahkan Anda ke konsol browser, tempat Anda dapat melihat pengecualian.
- Dalam produksi, bilah memberi tahu pengguna bahwa kesalahan telah terjadi dan merekomendasikan penyegaran browser.
Antarmuka pengguna untuk pengalaman penanganan kesalahan ini adalah bagian Blazor dari templat proyek. Tidak semua versi Blazor templat proyek menggunakan data-nosnippet
atribut untuk memberi sinyal ke browser untuk tidak menyimpan konten antarmuka pengguna kesalahan, tetapi semua versi Blazor dokumentasi menerapkan atribut .
Blazor Web AppDalam , sesuaikan pengalaman dalam MainLayout
komponen. Karena Pembantu Tag Lingkungan (misalnya, <environment include="Production">...</environment>
) tidak didukung dalam Razor komponen, contoh berikut menyuntikkan IHostEnvironment untuk mengonfigurasi pesan kesalahan untuk lingkungan yang berbeda.
Di bagian MainLayout.razor
atas :
@inject IHostEnvironment HostEnvironment
Buat atau ubah Blazor markup antarmuka pengguna kesalahan:
<div id="blazor-error-ui" data-nosnippet>
@if (HostEnvironment.IsProduction())
{
<span>An error has occurred.</span>
}
else
{
<span>An unhandled exception occurred.</span>
}
<a href="" class="reload">Reload</a>
<a class="dismiss">🗙</a>
</div>
Di aplikasi Blazor Server , sesuaikan pengalaman dalam Pages/_Host.cshtml
file. Contoh berikut menggunakan Pembantu Tag Lingkungan untuk mengonfigurasi pesan kesalahan untuk lingkungan yang berbeda.
Di aplikasi Blazor Server , sesuaikan pengalaman dalam Pages/_Layout.cshtml
file. Contoh berikut menggunakan Pembantu Tag Lingkungan untuk mengonfigurasi pesan kesalahan untuk lingkungan yang berbeda.
Di aplikasi Blazor Server , sesuaikan pengalaman dalam Pages/_Host.cshtml
file. Contoh berikut menggunakan Pembantu Tag Lingkungan untuk mengonfigurasi pesan kesalahan untuk lingkungan yang berbeda.
Buat atau ubah Blazor markup antarmuka pengguna kesalahan:
<div id="blazor-error-ui" data-nosnippet>
<environment include="Staging,Production">
An error has occurred.
</environment>
<environment include="Development">
An unhandled exception occurred.
</environment>
<a href="" class="reload">Reload</a>
<a class="dismiss">🗙</a>
</div>
Di aplikasi Blazor WebAssembly , sesuaikan pengalaman dalam wwwroot/index.html
file:
<div id="blazor-error-ui" data-nosnippet>
An unhandled error has occurred.
<a href="" class="reload">Reload</a>
<a class="dismiss">🗙</a>
</div>
Elemen blazor-error-ui
ini biasanya disembunyikan karena adanya display: none
gaya blazor-error-ui
kelas CSS di stylesheet yang dihasilkan secara otomatis dari aplikasi. Ketika kesalahan terjadi, kerangka kerja berlaku display: block
untuk elemen .
Elemen blazor-error-ui
biasanya tersembunyi karena adanya display: none
gaya blazor-error-ui
kelas CSS di lembar gaya situs di wwwroot/css
folder. Ketika kesalahan terjadi, kerangka kerja berlaku display: block
untuk elemen .
Kesalahan sirkuit terperinci
Bagian ini berlaku untuk Blazor Web Apps yang beroperasi melalui sirkuit.
Bagian ini berlaku untuk Blazor Server aplikasi.
Kesalahan sisi klien tidak menyertakan tumpukan panggilan dan tidak memberikan detail tentang penyebab kesalahan, tetapi log server berisi informasi tersebut. Untuk tujuan pengembangan, informasi kesalahan sirkuit sensitif dapat disediakan untuk klien dengan mengaktifkan kesalahan terperinci.
Atur CircuitOptions.DetailedErrors ke true
. Untuk informasi selengkapnya dan contohnya, lihat panduan ASP.NET CoreBlazorSignalR.
Alternatif untuk pengaturan CircuitOptions.DetailedErrors adalah mengatur DetailedErrors
kunci konfigurasi ke true
dalam file pengaturan lingkungan aplikasi Development
(appsettings.Development.json
). Selain itu, atur SignalR pengelogan sisi server (Microsoft.AspNetCore.SignalR
) ke Debug atau Lacak untuk pengelogan terperinci SignalR .
appsettings.Development.json
:
{
"DetailedErrors": true,
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information",
"Microsoft.AspNetCore.SignalR": "Debug"
}
}
}
Kunci DetailedErrors konfigurasi juga dapat diatur ke true
menggunakan ASPNETCORE_DETAILEDERRORS
variabel lingkungan dengan nilai true
pada Development
/Staging
server lingkungan atau pada sistem lokal Anda.
Peringatan
Selalu hindari mengekspos informasi kesalahan kepada klien di Internet, yang merupakan risiko keamanan.
Kesalahan terperinci untuk Razor penyajian sisi server komponen
Bagian ini berlaku untuk Blazor Web Apps.
RazorComponentsServiceOptions.DetailedErrors Gunakan opsi untuk mengontrol menghasilkan informasi terperinci tentang kesalahan untuk Razor penyajian sisi server komponen. Nilai defaultnya adalah false
.
Contoh berikut memungkinkan kesalahan terperinci:
builder.Services.AddRazorComponents(options =>
options.DetailedErrors = builder.Environment.IsDevelopment());
Peringatan
Hanya aktifkan kesalahan terperinci di Development
lingkungan. Kesalahan terperinci mungkin berisi informasi sensitif tentang aplikasi yang dapat digunakan pengguna berbahaya dalam serangan.
Contoh sebelumnya memberikan tingkat keamanan dengan menetapkan nilai DetailedErrors berdasarkan nilai yang dikembalikan oleh IsDevelopment. Saat aplikasi berada di Development
lingkungan, DetailedErrors diatur ke true
. Pendekatan ini tidak mudah karena dimungkinkan untuk menghosting aplikasi produksi di server publik di Development
lingkungan.
Mengelola pengecualian yang tidak tertangani dalam kode pengembang
Agar aplikasi berlanjut setelah kesalahan, aplikasi harus memiliki logika penanganan kesalahan. Bagian selanjutnya dari artikel ini menjelaskan sumber potensial pengecualian yang tidak tertangani.
Dalam produksi, jangan merender pesan pengecualian kerangka kerja atau jejak tumpukan di UI. Merender pesan pengecualian atau jejak tumpukan dapat:
- Mengungkapkan informasi sensitif kepada pengguna akhir.
- Bantu pengguna berbahaya menemukan kelemahan di aplikasi yang dapat membahayakan keamanan aplikasi, server, atau jaringan.
Pengecualian yang tidak tertangani untuk sirkuit
Bagian ini berlaku untuk aplikasi sisi server yang beroperasi melalui sirkuit.
Razor komponen dengan interaktivitas server diaktifkan bersifat stateful di server. Saat pengguna berinteraksi dengan komponen di server, mereka mempertahankan koneksi ke server yang dikenal sebagai sirkuit. Sirkuit ini menyimpan instans komponen aktif, ditambah banyak aspek status lainnya, seperti:
- Output komponen yang dirender terbaru.
- Kumpulan delegasi penanganan peristiwa saat ini yang dapat dipicu oleh peristiwa sisi klien.
Jika pengguna membuka aplikasi di beberapa tab browser, pengguna membuat beberapa sirkuit independen.
Blazor memperlakukan pengecualian yang paling tidak tertangani sebagai fatal bagi sirkuit tempat mereka terjadi. Jika sirkuit dihentikan karena pengecualian yang tidak tertangani, pengguna hanya dapat terus berinteraksi dengan aplikasi dengan memuat ulang halaman untuk membuat sirkuit baru. Sirkuit di luar sirkuit yang dihentikan, yang merupakan sirkuit untuk pengguna lain atau tab browser lainnya, tidak terpengaruh. Skenario ini mirip dengan aplikasi desktop yang mengalami crash. Aplikasi yang mengalami crash harus dimulai ulang, tetapi aplikasi lain tidak terpengaruh.
Kerangka kerja mengakhiri sirkuit ketika pengecualian yang tidak tertangani terjadi karena alasan berikut:
- Pengecualian yang tidak tertangani sering meninggalkan sirkuit dalam keadaan tidak terdefinisi.
- Operasi normal aplikasi tidak dapat dijamin setelah pengecualian yang tidak tertangani.
- Kerentanan keamanan dapat muncul di aplikasi jika sirkuit berlanjut dalam status tidak terdefinisi.
Penanganan pengecualian global
Untuk pendekatan menangani pengecualian secara global, lihat bagian berikut:
- Batas kesalahan: Berlaku untuk semua Blazor aplikasi.
- Penanganan pengecualian global alternatif: Berlaku untuk Blazor Server, , Blazor WebAssemblydan Blazor Web Apps (8.0 atau yang lebih baru) yang mengadopsi mode render interaktif global.
Batas kesalahan
Batas kesalahan memberikan pendekatan yang nyaman untuk menangani pengecualian. Komponen ErrorBoundary :
- Merender konten turunannya ketika kesalahan belum terjadi.
- Merender UI kesalahan ketika pengecualian yang tidak tertangani dilemparkan oleh komponen apa pun dalam batas kesalahan.
Untuk menentukan batas kesalahan, gunakan ErrorBoundary komponen untuk membungkus satu atau beberapa komponen lainnya. Batas kesalahan mengelola pengecualian yang tidak tertangani yang dilemparkan oleh komponen yang dibungkusnya.
<ErrorBoundary>
...
</ErrorBoundary>
Untuk menerapkan batas kesalahan dengan cara global, tambahkan batas di sekitar konten isi tata letak utama aplikasi.
Di MainLayout.razor
:
<article class="content px-4">
<ErrorBoundary>
@Body
</ErrorBoundary>
</article>
Dalam Blazor Web Apphal batas kesalahan hanya diterapkan ke komponen statis MainLayout
, batas hanya aktif selama penyajian sisi server statis (SSR statis). Batas tidak diaktifkan hanya karena komponen lebih jauh ke hierarki komponen bersifat interaktif.
Mode render interaktif tidak dapat diterapkan ke MainLayout
komponen karena parameter komponen Body
adalah RenderFragment delegasi, yang merupakan kode sewenang-wenang dan tidak dapat diserialisasikan. Untuk mengaktifkan interaktivitas secara luas untuk MainLayout
komponen dan rest komponen lebih jauh ke hierarki komponen, aplikasi harus mengadopsi mode render interaktif global dengan menerapkan mode render interaktif ke HeadOutlet
instans komponen dan Routes
di komponen root aplikasi, yang biasanya App
merupakan komponen. Contoh berikut mengadopsi mode render Server Interaktif (InteractiveServer
) secara global.
Di Components/App.razor
:
<HeadOutlet @rendermode="InteractiveServer" />
...
<Routes @rendermode="InteractiveServer" />
Jika Anda lebih suka tidak mengaktifkan interaktivitas global, letakkan batas kesalahan lebih jauh ke hierarki komponen. Konsep penting yang perlu diingat adalah bahwa di mana pun batas kesalahan ditempatkan:
- Jika komponen tempat batas kesalahan ditempatkan tidak interaktif, batas kesalahan hanya mampu mengaktifkan di server selama SSR statis. Misalnya, batas dapat diaktifkan ketika kesalahan dilemparkan dalam metode siklus hidup komponen tetapi tidak untuk peristiwa yang dipicu oleh interaktivitas pengguna dalam komponen, seperti kesalahan yang dilemparkan oleh handler klik tombol.
- Jika komponen tempat batas kesalahan ditempatkan interaktif, batas kesalahan mampu mengaktifkan komponen interaktif yang dibungkusnya.
Catatan
Pertimbangan sebelumnya tidak relevan untuk aplikasi mandiri Blazor WebAssembly karena penyajian Blazor WebAssembly sisi klien (CSR) aplikasi sepenuhnya interaktif.
Pertimbangkan contoh berikut, di mana pengecualian yang dilemparkan oleh komponen penghitung yang disematkan ditangkap oleh batas kesalahan dalam Home
komponen, yang mengadopsi mode render interaktif.
EmbeddedCounter.razor
:
<h1>Embedded Counter</h1>
<p role="status">Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
if (currentCount > 5)
{
throw new InvalidOperationException("Current count is too big!");
}
}
}
Home.razor
:
@page "/"
@rendermode InteractiveServer
<PageTitle>Home</PageTitle>
<h1>Home</h1>
<ErrorBoundary>
<EmbeddedCounter />
</ErrorBoundary>
Pertimbangkan contoh berikut, di mana pengecualian yang dilemparkan oleh komponen penghitung yang disematkan ditangkap oleh batas kesalahan dalam Home
komponen.
EmbeddedCounter.razor
:
<h1>Embedded Counter</h1>
<p role="status">Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
if (currentCount > 5)
{
throw new InvalidOperationException("Current count is too big!");
}
}
}
Home.razor
:
@page "/"
<PageTitle>Home</PageTitle>
<h1>Home</h1>
<ErrorBoundary>
<EmbeddedCounter />
</ErrorBoundary>
Jika pengecualian yang tidak tertangani dilemparkan selama currentCount
lebih dari lima:
- Kesalahan dicatat secara normal (
System.InvalidOperationException: Current count is too big!
). - Pengecualian ditangani oleh batas kesalahan.
- UI kesalahan default dirender oleh batas kesalahan.
Komponen ErrorBoundary merender elemen kosong <div>
menggunakan blazor-error-boundary
kelas CSS untuk konten kesalahannya. Warna, teks, dan ikon untuk antarmuka pengguna default didefinisikan dalam lembar gaya aplikasi di wwwroot
folder, sehingga Anda bebas untuk menyesuaikan antarmuka pengguna kesalahan.
Untuk mengubah konten kesalahan default:
- Bungkus komponen batas kesalahan dalam ChildContent properti .
- Atur ErrorContent properti ke konten kesalahan.
Contoh berikut membungkus EmbeddedCounter
komponen dan menyediakan konten kesalahan kustom:
<ErrorBoundary>
<ChildContent>
<EmbeddedCounter />
</ChildContent>
<ErrorContent>
<p class="errorUI">😈 A rotten gremlin got us. Sorry!</p>
</ErrorContent>
</ErrorBoundary>
Untuk contoh sebelumnya, lembar gaya aplikasi mungkin menyertakan errorUI
kelas CSS untuk menata konten. Konten kesalahan dirender dari ErrorContent properti tanpa elemen tingkat blok. Elemen tingkat blok, seperti elemen pembagian (<div>
) atau paragraf (<p>
), dapat membungkus markup konten kesalahan, tetapi tidak diperlukan.
Secara opsional, gunakan konteks (@context
) ErrorContent untuk mendapatkan data kesalahan:
<ErrorContent>
@context.HelpLink
</ErrorContent>
juga ErrorContent dapat memberi nama konteks. Dalam contoh berikut, konteks diberi nama exception
:
<ErrorContent Context="exception">
@exception.HelpLink
</ErrorContent>
Peringatan
Selalu hindari mengekspos informasi kesalahan kepada klien di Internet, yang merupakan risiko keamanan.
Jika batas kesalahan ditentukan dalam tata letak aplikasi, antarmuka pengguna kesalahan terlihat terlepas dari halaman mana pengguna menavigasi setelah kesalahan terjadi. Sebaiknya cakupan batas kesalahan secara sempit dalam sebagian besar skenario. Jika Anda secara luas mencakup batas kesalahan, Anda dapat mengatur ulang ke status non-kesalahan pada peristiwa navigasi halaman berikutnya dengan memanggil metode batas Recover kesalahan.
Di MainLayout.razor
:
- Tambahkan bidang untuk ErrorBoundary menangkap referensi ke bidang tersebut dengan direktif
@ref
atribut. OnParameterSet
Dalam metode siklus hidup, Anda dapat memicu pemulihan pada batas kesalahan dengan Recover untuk menghapus kesalahan saat pengguna menavigasi ke komponen yang berbeda.
...
<ErrorBoundary @ref="errorBoundary">
@Body
</ErrorBoundary>
...
@code {
private ErrorBoundary? errorBoundary;
protected override void OnParametersSet()
{
errorBoundary?.Recover();
}
}
Untuk menghindari perulangan tak terbatas di mana pemulihan hanya merender komponen yang melemparkan kesalahan lagi, jangan panggil Recover dari logika penyajian. Hanya panggil Recover saat:
- Pengguna melakukan gerakan UI, seperti memilih tombol untuk menunjukkan bahwa mereka ingin mencoba kembali prosedur atau ketika pengguna menavigasi ke komponen baru.
- Logika tambahan yang dijalankan juga menghapus pengecualian. Ketika komponen dirender ulang, kesalahan tidak terulang kembali.
Contoh berikut memungkinkan pengguna untuk pulih dari pengecualian dengan tombol:
<ErrorBoundary @ref="errorBoundary">
<ChildContent>
<EmbeddedCounter />
</ChildContent>
<ErrorContent>
<div class="alert alert-danger" role="alert">
<p class="fs-3 fw-bold">😈 A rotten gremlin got us. Sorry!</p>
<p>@context.HelpLink</p>
<button class="btn btn-info" @onclick="_ => errorBoundary?.Recover()">
Clear
</button>
</div>
</ErrorContent>
</ErrorBoundary>
@code {
private ErrorBoundary? errorBoundary;
}
Anda juga dapat subkelas ErrorBoundary untuk pemrosesan kustom dengan mengambil alih OnErrorAsync. Contoh berikut hanya mencatat kesalahan, tetapi Anda dapat menerapkan kode penanganan kesalahan apa pun yang Anda inginkan. Anda dapat menghapus baris yang mengembalikan jika CompletedTask kode Anda menunggu tugas asinkron.
CustomErrorBoundary.razor
:
@inherits ErrorBoundary
@inject ILogger<CustomErrorBoundary> Logger
@if (CurrentException is null)
{
@ChildContent
}
else if (ErrorContent is not null)
{
@ErrorContent(CurrentException)
}
@code {
protected override Task OnErrorAsync(Exception ex)
{
Logger.LogError(ex, "😈 A rotten gremlin got us. Sorry!");
return Task.CompletedTask;
}
}
Contoh sebelumnya juga dapat diimplementasikan sebagai kelas.
CustomErrorBoundary.cs
:
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
namespace BlazorSample;
public class CustomErrorBoundary : ErrorBoundary
{
[Inject]
ILogger<CustomErrorBoundary> Logger { get; set; } = default!;
protected override Task OnErrorAsync(Exception ex)
{
Logger.LogError(ex, "😈 A rotten gremlin got us. Sorry!");
return Task.CompletedTask;
}
}
Salah satu implementasi sebelumnya yang digunakan dalam komponen:
<CustomErrorBoundary>
...
</CustomErrorBoundary>
Penanganan pengecualian global alternatif
Pendekatan yang dijelaskan di bagian ini berlaku untuk Blazor Server, , dan Blazor Web Appyang mengadopsi mode render interaktif global (InteractiveServer
, , InteractiveWebAssembly
atau InteractiveAuto
Blazor WebAssembly). Pendekatan ini tidak berfungsi dengan Blazor Web Appyang mengadopsi mode render per halaman/komponen atau penyajian sisi server statis (SSR statis) karena pendekatan bergantung pada CascadingValue
/CascadingParameter
, yang tidak berfungsi di seluruh batas mode render atau dengan komponen yang mengadopsi SSR statis.
Alternatif untuk menggunakan Batas kesalahan (ErrorBoundary) adalah meneruskan komponen kesalahan kustom sebagai CascadingValue
komponen ke anak. Keuntungan menggunakan komponen daripada menggunakan layanan yang disuntikkan atau implementasi pencatat kustom adalah bahwa komponen bertingkat dapat merender konten dan menerapkan gaya CSS saat kesalahan terjadi.
Contoh komponen berikut ProcessError
hanya mencatat kesalahan, tetapi metode komponen dapat memproses kesalahan dengan cara apa pun yang diperlukan oleh aplikasi, termasuk melalui penggunaan beberapa metode pemrosesan kesalahan.
ProcessError.razor
:
@inject ILogger<ProcessError> Logger
<CascadingValue Value="this">
@ChildContent
</CascadingValue>
@code {
[Parameter]
public RenderFragment? ChildContent { get; set; }
public void LogError(Exception ex)
{
Logger.LogError("ProcessError.LogError: {Type} Message: {Message}",
ex.GetType(), ex.Message);
// Call StateHasChanged if LogError directly participates in
// rendering. If LogError only logs or records the error,
// there's no need to call StateHasChanged.
//StateHasChanged();
}
}
Catatan
Untuk informasi selengkapnya tentang RenderFragment, lihat komponen ASP.NET CoreRazor.
Saat menggunakan pendekatan ini dalam Blazor Web App, buka Routes
komponen dan bungkus Router komponen (<Router>...</Router>
) dengan ProcessError
komponen . Hal ini memungkinkan ProcessError
komponen untuk melakukan cascade ke komponen aplikasi mana pun di mana ProcessError
komponen diterima sebagai CascadingParameter
.
Di Routes.razor
:
<ProcessError>
<Router ...>
...
</Router>
</ProcessError>
Saat menggunakan pendekatan ini dalam aplikasi Blazor Server atau Blazor WebAssembly , buka App
komponen , bungkus Router komponen (<Router>...</Router>
) dengan ProcessError
komponen . Hal ini memungkinkan ProcessError
komponen untuk melakukan cascade ke komponen aplikasi mana pun di mana ProcessError
komponen diterima sebagai CascadingParameter
.
Di App.razor
:
<ProcessError>
<Router ...>
...
</Router>
</ProcessError>
Untuk memproses kesalahan dalam komponen:
Menunjuk
ProcessError
komponen sebagaiCascadingParameter
di@code
blok. Dalam contohCounter
komponen dalam aplikasi berdasarkan Blazor templat proyek, tambahkan properti berikutProcessError
:[CascadingParameter] public ProcessError? ProcessError { get; set; }
Panggil metode pemrosesan kesalahan di blok mana pun
catch
dengan jenis pengecualian yang sesuai. Komponen contohProcessError
hanya menawarkan satuLogError
metode, tetapi komponen pemrosesan kesalahan dapat menyediakan sejumlah metode pemrosesan kesalahan untuk mengatasi persyaratan pemrosesan kesalahan alternatif di seluruh aplikasi. Contoh blok komponen@code
berikutCounter
mencakupProcessError
parameter bertingkat dan menjebak pengecualian untuk pengelogan ketika jumlahnya lebih besar dari lima:@code { private int currentCount = 0; [CascadingParameter] public ProcessError? ProcessError { get; set; } private void IncrementCount() { try { currentCount++; if (currentCount > 5) { throw new InvalidOperationException("Current count is over five!"); } } catch (Exception ex) { ProcessError?.LogError(ex); } } }
Kesalahan yang dicatat:
fail: {COMPONENT NAMESPACE}.ProcessError[0]
ProcessError.LogError: System.InvalidOperationException Message: Current count is over five!
Jika metode secara LogError
langsung berpartisipasi dalam penyajian, seperti memperlihatkan bilah pesan kesalahan kustom atau mengubah gaya CSS elemen yang dirender, panggil StateHasChanged
di akhir LogError
metode untuk merender UI.
Karena pendekatan di bagian ini menangani kesalahan dengan try-catch
pernyataan, koneksi aplikasi SignalR antara klien dan server tidak rusak ketika kesalahan terjadi dan sirkuit tetap hidup. Pengecualian lain yang tidak tertangani tetap fatal bagi sirkuit. Untuk informasi selengkapnya, lihat bagian tentang bagaimana sirkuit bereaksi terhadap pengecualian yang tidak tertangani.
Aplikasi dapat menggunakan komponen pemrosesan kesalahan sebagai nilai berkala untuk memproses kesalahan dengan cara terpusat.
Komponen berikut ProcessError
meneruskan dirinya sebagai CascadingValue
komponen ke anak. Contoh berikut hanya mencatat kesalahan, tetapi metode komponen dapat memproses kesalahan dengan cara apa pun yang diperlukan oleh aplikasi, termasuk melalui penggunaan beberapa metode pemrosesan kesalahan. Keuntungan menggunakan komponen daripada menggunakan layanan yang disuntikkan atau implementasi pencatat kustom adalah bahwa komponen bertingkat dapat merender konten dan menerapkan gaya CSS saat kesalahan terjadi.
ProcessError.razor
:
@using Microsoft.Extensions.Logging
@inject ILogger<ProcessError> Logger
<CascadingValue Value="this">
@ChildContent
</CascadingValue>
@code {
[Parameter]
public RenderFragment ChildContent { get; set; }
public void LogError(Exception ex)
{
Logger.LogError("ProcessError.LogError: {Type} Message: {Message}",
ex.GetType(), ex.Message);
}
}
Catatan
Untuk informasi selengkapnya tentang RenderFragment, lihat komponen ASP.NET CoreRazor.
App
Dalam komponen, bungkus Router komponen dengan ProcessError
komponen . Hal ini memungkinkan ProcessError
komponen untuk melakukan cascade ke komponen aplikasi mana pun di mana ProcessError
komponen diterima sebagai CascadingParameter
.
App.razor
:
<ProcessError>
<Router ...>
...
</Router>
</ProcessError>
Untuk memproses kesalahan dalam komponen:
Tetapkan
ProcessError
komponen sebagaiCascadingParameter
dalam@code
blok:[CascadingParameter] public ProcessError ProcessError { get; set; }
Panggil metode pemrosesan kesalahan di blok mana pun
catch
dengan jenis pengecualian yang sesuai. Komponen contohProcessError
hanya menawarkan satuLogError
metode, tetapi komponen pemrosesan kesalahan dapat menyediakan sejumlah metode pemrosesan kesalahan untuk mengatasi persyaratan pemrosesan kesalahan alternatif di seluruh aplikasi.try { ... } catch (Exception ex) { ProcessError.LogError(ex); }
Menggunakan komponen dan LogError
metode contoh ProcessError
sebelumnya, konsol alat pengembang browser menunjukkan kesalahan yang terperangkap dan dicatat:
fail: {COMPONENT NAMESPACE}.Shared.ProcessError[0]
ProcessError.LogError: System.NullReferenceException Message: Object reference not set to an instance of an object.
Jika metode secara LogError
langsung berpartisipasi dalam penyajian, seperti memperlihatkan bilah pesan kesalahan kustom atau mengubah gaya CSS elemen yang dirender, panggil StateHasChanged
di akhir LogError
metode untuk merender UI.
Karena pendekatan di bagian ini menangani kesalahan dengan try-catch
pernyataan, Blazor koneksi aplikasi SignalR antara klien dan server tidak rusak ketika kesalahan terjadi dan sirkuit tetap hidup. Pengecualian yang tidak tertangani berakibat fatal bagi sirkuit. Untuk informasi selengkapnya, lihat bagian tentang bagaimana sirkuit bereaksi terhadap pengecualian yang tidak tertangani.
Kesalahan log dengan penyedia persisten
Jika terjadi pengecualian yang tidak tertangani, pengecualian dicatat ke ILogger instans yang dikonfigurasi dalam kontainer layanan. Blazor output konsol log aplikasi dengan Penyedia Pengelogan Konsol. Pertimbangkan untuk masuk ke lokasi di server (atau API web backend untuk aplikasi sisi klien) dengan penyedia yang mengelola ukuran log dan rotasi log. Atau, aplikasi dapat menggunakan layanan Manajemen Performa Aplikasi (APM), seperti Azure Application Insights (Azure Monitor).
Catatan
Fitur Application Insights asli untuk mendukung aplikasi sisi klien dan dukungan kerangka kerja asli Blazor untuk Google Analytics mungkin tersedia dalam rilis teknologi ini di masa mendatang. Untuk informasi selengkapnya, lihat Mendukung App Insights di Blazor Sisi Klien WASM (microsoft/ApplicationInsights-dotnet #2143) dan Analitik dan diagnostik Web (termasuk tautan ke implementasi komunitas) (dotnet/aspnetcore #5461). Sementara itu, aplikasi sisi klien dapat menggunakan Application Insights JavaScript SDK dengan JS interop untuk mencatat kesalahan langsung ke Application Insights dari aplikasi sisi klien.
Selama pengembangan dalam aplikasi yang Blazor beroperasi melalui sirkuit, aplikasi biasanya mengirim detail lengkap pengecualian ke konsol browser untuk membantu penelusuran kesalahan. Dalam produksi, kesalahan terperinci tidak dikirim ke klien, tetapi detail lengkap pengecualian dicatat di server.
Anda harus memutuskan insiden mana yang akan dicatat dan tingkat keparahan insiden yang dicatat. Pengguna yang bermusuhan mungkin dapat memicu kesalahan dengan sengaja. Misalnya, jangan mencatat insiden dari kesalahan di mana yang tidak diketahui ProductId
disediakan dalam URL komponen yang menampilkan detail produk. Tidak semua kesalahan harus diperlakukan sebagai insiden untuk pengelogan.
Untuk informasi lebih lanjut, baca artikel berikut:
- Pengelogan Blazor ASP.NET Core
- Menangani kesalahan di ASP.NET Core‡
- Membuat API web dengan ASP.NET Core
‡Berlaku untuk aplikasi sisi Blazor server dan aplikasi ASP.NET Core sisi server lainnya yang merupakan aplikasi backend API web untuk Blazor. Aplikasi sisi klien dapat menjebak dan mengirim informasi kesalahan pada klien ke API web, yang mencatat informasi kesalahan ke penyedia pengelogan persisten.
Jika terjadi pengecualian yang tidak tertangani, pengecualian dicatat ke ILogger instans yang dikonfigurasi dalam kontainer layanan. Blazor output konsol log aplikasi dengan Penyedia Pengelogan Konsol. Pertimbangkan untuk masuk ke lokasi yang lebih permanen di server dengan mengirim informasi kesalahan ke API web backend yang menggunakan penyedia pengelogan dengan manajemen ukuran log dan rotasi log. Atau, aplikasi API web backend dapat menggunakan layanan Manajemen Performa Aplikasi (APM), seperti Azure Application Insights (Azure Monitor)†, untuk merekam informasi kesalahan yang diterimanya dari klien.
Anda harus memutuskan insiden mana yang akan dicatat dan tingkat keparahan insiden yang dicatat. Pengguna yang bermusuhan mungkin dapat memicu kesalahan dengan sengaja. Misalnya, jangan mencatat insiden dari kesalahan di mana yang tidak diketahui ProductId
disediakan dalam URL komponen yang menampilkan detail produk. Tidak semua kesalahan harus diperlakukan sebagai insiden untuk pengelogan.
Untuk informasi lebih lanjut, baca artikel berikut:
- Pengelogan Blazor ASP.NET Core
- Menangani kesalahan di ASP.NET Core‡
- Membuat API web dengan ASP.NET Core
†Native Application Insights untuk mendukung aplikasi sisi klien dan dukungan kerangka kerja asli Blazor untuk Google Analytics mungkin tersedia dalam rilis teknologi ini di masa mendatang. Untuk informasi selengkapnya, lihat Mendukung App Insights di Blazor Sisi Klien WASM (microsoft/ApplicationInsights-dotnet #2143) dan Analitik dan diagnostik Web (termasuk tautan ke implementasi komunitas) (dotnet/aspnetcore #5461). Sementara itu, aplikasi sisi klien dapat menggunakan Application Insights JavaScript SDK dengan JS interop untuk mencatat kesalahan langsung ke Application Insights dari aplikasi sisi klien.
‡Berlaku untuk aplikasi ASP.NET Core sisi server yang merupakan aplikasi backend API web untuk Blazor aplikasi. Aplikasi sisi klien menjebak dan mengirim informasi kesalahan ke API web, yang mencatat informasi kesalahan ke penyedia pengelogan persisten.
Tempat di mana kesalahan dapat terjadi
Kerangka kerja dan kode aplikasi dapat memicu pengecualian yang tidak tertangani di salah satu lokasi berikut, yang dijelaskan lebih lanjut di bagian berikut dari artikel ini:
Instansiasi komponen
Saat Blazor membuat instans komponen:
- Konstruktor komponen dipanggil.
- Konstruktor layanan DI yang disediakan ke konstruktor komponen melalui
@inject
direktif atau[Inject]
atribut dipanggil.
Kesalahan dalam konstruktor yang dijalankan atau setter untuk properti apa pun [Inject]
menghasilkan pengecualian yang tidak tertangani dan menghentikan kerangka kerja membuat instans komponen. Jika aplikasi beroperasi melalui sirkuit, sirkuit gagal. Jika logika konstruktor dapat melemparkan pengecualian, aplikasi harus menjebak pengecualian menggunakan try-catch
pernyataan dengan penanganan kesalahan dan pengelogan.
Metode siklus hidup
Selama masa pakai komponen, Blazor memanggil metode siklus hidup. Jika ada metode siklus hidup yang melemparkan pengecualian, secara sinkron atau asinkron, pengecualiannya fatal bagi sirkuit. Agar komponen menangani kesalahan dalam metode siklus hidup, tambahkan logika penanganan kesalahan.
Dalam contoh berikut di mana OnParametersSetAsync memanggil metode untuk mendapatkan produk:
- Pengecualian yang dilemparkan dalam metode ditangani
ProductRepository.GetProductByIdAsync
olehtry-catch
pernyataan. catch
Ketika blok dijalankan:loadFailed
diatur ketrue
, yang digunakan untuk menampilkan pesan kesalahan kepada pengguna.- Kesalahan dicatat.
@page "/product-details/{ProductId:int?}"
@inject ILogger<ProductDetails> Logger
@inject IProductRepository Product
<PageTitle>Product Details</PageTitle>
<h1>Product Details Example</h1>
@if (details != null)
{
<h2>@details.ProductName</h2>
<p>
@details.Description
<a href="@details.Url">Company Link</a>
</p>
}
else if (loadFailed)
{
<h1>Sorry, we could not load this product due to an error.</h1>
}
else
{
<h1>Loading...</h1>
}
@code {
private ProductDetail? details;
private bool loadFailed;
[Parameter]
public int ProductId { get; set; }
protected override async Task OnParametersSetAsync()
{
try
{
loadFailed = false;
// Reset details to null to display the loading indicator
details = null;
details = await Product.GetProductByIdAsync(ProductId);
}
catch (Exception ex)
{
loadFailed = true;
Logger.LogWarning(ex, "Failed to load product {ProductId}", ProductId);
}
}
public class ProductDetail
{
public string? ProductName { get; set; }
public string? Description { get; set; }
public string? Url { get; set; }
}
/*
* Register the service in Program.cs:
* using static BlazorSample.Components.Pages.ProductDetails;
* builder.Services.AddScoped<IProductRepository, ProductRepository>();
*/
public interface IProductRepository
{
public Task<ProductDetail> GetProductByIdAsync(int id);
}
public class ProductRepository : IProductRepository
{
public Task<ProductDetail> GetProductByIdAsync(int id)
{
return Task.FromResult(
new ProductDetail()
{
ProductName = "Flowbee ",
Description = "The Revolutionary Haircutting System You've Come to Love!",
Url = "https://flowbee.com/"
});
}
}
}
@page "/product-details/{ProductId:int?}"
@inject ILogger<ProductDetails> Logger
@inject IProductRepository Product
<PageTitle>Product Details</PageTitle>
<h1>Product Details Example</h1>
@if (details != null)
{
<h2>@details.ProductName</h2>
<p>
@details.Description
<a href="@details.Url">Company Link</a>
</p>
}
else if (loadFailed)
{
<h1>Sorry, we could not load this product due to an error.</h1>
}
else
{
<h1>Loading...</h1>
}
@code {
private ProductDetail? details;
private bool loadFailed;
[Parameter]
public int ProductId { get; set; }
protected override async Task OnParametersSetAsync()
{
try
{
loadFailed = false;
// Reset details to null to display the loading indicator
details = null;
details = await Product.GetProductByIdAsync(ProductId);
}
catch (Exception ex)
{
loadFailed = true;
Logger.LogWarning(ex, "Failed to load product {ProductId}", ProductId);
}
}
public class ProductDetail
{
public string? ProductName { get; set; }
public string? Description { get; set; }
public string? Url { get; set; }
}
/*
* Register the service in Program.cs:
* using static BlazorSample.Components.Pages.ProductDetails;
* builder.Services.AddScoped<IProductRepository, ProductRepository>();
*/
public interface IProductRepository
{
public Task<ProductDetail> GetProductByIdAsync(int id);
}
public class ProductRepository : IProductRepository
{
public Task<ProductDetail> GetProductByIdAsync(int id)
{
return Task.FromResult(
new ProductDetail()
{
ProductName = "Flowbee ",
Description = "The Revolutionary Haircutting System You've Come to Love!",
Url = "https://flowbee.com/"
});
}
}
}
@page "/product-details/{ProductId:int}"
@using Microsoft.Extensions.Logging
@inject ILogger<ProductDetails> Logger
@inject IProductRepository ProductRepository
@if (details != null)
{
<h1>@details.ProductName</h1>
<p>@details.Description</p>
}
else if (loadFailed)
{
<h1>Sorry, we could not load this product due to an error.</h1>
}
else
{
<h1>Loading...</h1>
}
@code {
private ProductDetail? details;
private bool loadFailed;
[Parameter]
public int ProductId { get; set; }
protected override async Task OnParametersSetAsync()
{
try
{
loadFailed = false;
// Reset details to null to display the loading indicator
details = null;
details = await ProductRepository.GetProductByIdAsync(ProductId);
}
catch (Exception ex)
{
loadFailed = true;
Logger.LogWarning(ex, "Failed to load product {ProductId}", ProductId);
}
}
public class ProductDetail
{
public string? ProductName { get; set; }
public string? Description { get; set; }
}
public interface IProductRepository
{
public Task<ProductDetail> GetProductByIdAsync(int id);
}
}
@page "/product-details/{ProductId:int}"
@using Microsoft.Extensions.Logging
@inject ILogger<ProductDetails> Logger
@inject IProductRepository ProductRepository
@if (details != null)
{
<h1>@details.ProductName</h1>
<p>@details.Description</p>
}
else if (loadFailed)
{
<h1>Sorry, we could not load this product due to an error.</h1>
}
else
{
<h1>Loading...</h1>
}
@code {
private ProductDetail? details;
private bool loadFailed;
[Parameter]
public int ProductId { get; set; }
protected override async Task OnParametersSetAsync()
{
try
{
loadFailed = false;
// Reset details to null to display the loading indicator
details = null;
details = await ProductRepository.GetProductByIdAsync(ProductId);
}
catch (Exception ex)
{
loadFailed = true;
Logger.LogWarning(ex, "Failed to load product {ProductId}", ProductId);
}
}
public class ProductDetail
{
public string? ProductName { get; set; }
public string? Description { get; set; }
}
public interface IProductRepository
{
public Task<ProductDetail> GetProductByIdAsync(int id);
}
}
@page "/product-details/{ProductId:int}"
@using Microsoft.Extensions.Logging
@inject ILogger<ProductDetails> Logger
@inject IProductRepository ProductRepository
@if (details != null)
{
<h1>@details.ProductName</h1>
<p>@details.Description</p>
}
else if (loadFailed)
{
<h1>Sorry, we could not load this product due to an error.</h1>
}
else
{
<h1>Loading...</h1>
}
@code {
private ProductDetail details;
private bool loadFailed;
[Parameter]
public int ProductId { get; set; }
protected override async Task OnParametersSetAsync()
{
try
{
loadFailed = false;
// Reset details to null to display the loading indicator
details = null;
details = await ProductRepository.GetProductByIdAsync(ProductId);
}
catch (Exception ex)
{
loadFailed = true;
Logger.LogWarning(ex, "Failed to load product {ProductId}", ProductId);
}
}
public class ProductDetail
{
public string ProductName { get; set; }
public string Description { get; set; }
}
public interface IProductRepository
{
public Task<ProductDetail> GetProductByIdAsync(int id);
}
}
@page "/product-details/{ProductId:int}"
@using Microsoft.Extensions.Logging
@inject ILogger<ProductDetails> Logger
@inject IProductRepository ProductRepository
@if (details != null)
{
<h1>@details.ProductName</h1>
<p>@details.Description</p>
}
else if (loadFailed)
{
<h1>Sorry, we could not load this product due to an error.</h1>
}
else
{
<h1>Loading...</h1>
}
@code {
private ProductDetail details;
private bool loadFailed;
[Parameter]
public int ProductId { get; set; }
protected override async Task OnParametersSetAsync()
{
try
{
loadFailed = false;
// Reset details to null to display the loading indicator
details = null;
details = await ProductRepository.GetProductByIdAsync(ProductId);
}
catch (Exception ex)
{
loadFailed = true;
Logger.LogWarning(ex, "Failed to load product {ProductId}", ProductId);
}
}
public class ProductDetail
{
public string ProductName { get; set; }
public string Description { get; set; }
}
public interface IProductRepository
{
public Task<ProductDetail> GetProductByIdAsync(int id);
}
}
Logika penyajian
Markup deklaratif dalam file komponen () dikompilasi Razor ke dalam metode C# yang disebut BuildRenderTree..razor
Saat komponen merender, BuildRenderTree menjalankan dan membangun struktur data yang menjelaskan elemen, teks, dan komponen turunan dari komponen yang dirender.
Logika penyajian dapat melemparkan pengecualian. Contoh skenario ini terjadi ketika @someObject.PropertyName
dievaluasi tetapi @someObject
adalah null
. Untuk Blazor aplikasi yang beroperasi melalui sirkuit, pengecualian yang tidak tertangani yang dilemparkan oleh logika penyajian berakibat fatal bagi sirkuit aplikasi.
Untuk mencegah NullReferenceException dalam logika penyajian, periksa null
objek sebelum mengakses anggotanya. Dalam contoh berikut, person.Address
properti tidak diakses jika person.Address
adalah null
:
@if (person.Address != null)
{
<div>@person.Address.Line1</div>
<div>@person.Address.Line2</div>
<div>@person.Address.City</div>
<div>@person.Address.Country</div>
}
Kode sebelumnya mengasumsikan bahwa person
bukan null
. Seringkali, struktur kode menjamin bahwa objek ada pada saat komponen dirender. Dalam kasus tersebut, tidak perlu memeriksa null
logika penyajian. Dalam contoh sebelumnya, person
mungkin dijamin ada karena person
dibuat saat komponen dibuat, seperti yang ditunjukkan contoh berikut:
@code {
private Person person = new();
...
}
Penangan kejadian
Kode sisi klien memicu pemanggilan kode C# saat penanganan aktivitas dibuat menggunakan:
@onclick
@onchange
- Atribut lain
@on...
@bind
Kode penanganan aktivitas mungkin melemparkan pengecualian yang tidak tertangani dalam skenario ini.
Jika aplikasi memanggil kode yang dapat gagal karena alasan eksternal, pengecualian perangkap menggunakan try-catch
pernyataan dengan penanganan kesalahan dan pengelogan.
Jika penanganan aktivitas melemparkan pengecualian yang tidak tertangani (misalnya, kueri database gagal) yang tidak terperangkap dan ditangani oleh kode pengembang:
- Kerangka kerja mencatat pengecualian.
- Dalam aplikasi yang Blazor beroperasi melalui sirkuit, pengecualiannya berakibat fatal bagi sirkuit aplikasi.
Pembuangan komponen
Komponen dapat dihapus dari UI, misalnya, karena pengguna telah menavigasi ke halaman lain. Ketika komponen yang menerapkan System.IDisposable dihapus dari UI, kerangka kerja memanggil metode komponen Dispose .
Jika metode komponen Dispose
melemparkan pengecualian yang tidak tertangani dalam aplikasi yang Blazor beroperasi melalui sirkuit, pengecualiannya berakibat fatal bagi sirkuit aplikasi.
Jika logika pembuangan dapat melemparkan pengecualian, aplikasi harus menjebak pengecualian menggunakan try-catch
pernyataan dengan penanganan kesalahan dan pengelogan.
Untuk informasi selengkapnya tentang pembuangan komponen, lihat siklus hidup komponen ASP.NET CoreRazor.
Interop JavaScript
IJSRuntime terdaftar oleh Blazor kerangka kerja. IJSRuntime.InvokeAsync memungkinkan kode .NET untuk melakukan panggilan asinkron ke runtime JavaScript (JS) di browser pengguna.
Kondisi berikut berlaku untuk penanganan kesalahan dengan InvokeAsync:
- Jika panggilan gagal InvokeAsync secara sinkron, pengecualian .NET terjadi. Panggilan ke InvokeAsync mungkin gagal, misalnya, karena argumen yang disediakan tidak dapat diserialisasikan. Kode pengembang harus menangkap pengecualian. Jika kode aplikasi dalam metode penanganan aktivitas atau siklus hidup komponen tidak menangani pengecualian dalam aplikasi yang Blazor beroperasi melalui sirkuit, pengecualian yang dihasilkan berakibat fatal bagi sirkuit aplikasi.
- Jika panggilan gagal InvokeAsync secara asinkron, .NET Task gagal. Panggilan ke InvokeAsync mungkin gagal, misalnya, karena JSkode -side melempar pengecualian atau mengembalikan
Promise
yang diselesaikan sebagairejected
. Kode pengembang harus menangkap pengecualian. Jika menggunakanawait
operator, pertimbangkan untuk membungkus panggilan metode dalamtry-catch
pernyataan dengan penanganan kesalahan dan pengelogan. Jika tidak, dalam aplikasi yang Blazor beroperasi melalui sirkuit, kode yang gagal menghasilkan pengecualian yang tidak tertangani yang fatal bagi sirkuit aplikasi. - Panggilan ke InvokeAsync harus selesai dalam periode tertentu atau waktu panggilan habis. Periode batas waktu default adalah satu menit. Batas waktu melindungi kode dari kehilangan konektivitas jaringan atau JS kode yang tidak pernah mengirim kembali pesan penyelesaian. Jika waktu panggilan habis, hasilnya System.Threading.Tasks gagal dengan OperationCanceledException. Perangkap dan proses pengecualian dengan pengelogan.
Demikian pula, JS kode dapat memulai panggilan ke metode .NET yang ditunjukkan oleh [JSInvokable]
atribut . Jika metode .NET ini melemparkan pengecualian yang tidak tertangani:
- Dalam aplikasi yang Blazor beroperasi melalui sirkuit, pengecualian tidak diperlakukan sebagai fatal bagi sirkuit aplikasi.
- - JSsisi
Promise
ditolak.
Anda memiliki opsi untuk menggunakan kode penanganan kesalahan di sisi .NET atau sisi JS panggilan metode.
Untuk informasi lebih lanjut, baca artikel berikut:
- Memanggil fungsi JavaScript dari metode .NET di Blazor ASP.NET Core
- Memanggil metode .NET dari fungsi JavaScript di Blazor ASP.NET Core
Pra-penyajian
Razor komponen telah dirender secara default sehingga markup HTML yang dirender dikembalikan sebagai bagian dari permintaan HTTP awal pengguna.
Dalam aplikasi yang Blazor beroperasi melalui sirkuit, pra-penyajian berfungsi dengan:
- Membuat sirkuit baru untuk semua komponen yang telah dirender sebelumnya yang merupakan bagian dari halaman yang sama.
- Membuat HTML awal.
- Memperlakukan sirkuit sampai
disconnected
browser pengguna membuat SignalR koneksi kembali ke server yang sama. Ketika koneksi dibuat, interaktivitas pada sirkuit dilanjutkan dan markup HTML komponen diperbarui.
Untuk komponen sisi klien yang telah dirender sebelumnya, prarender bekerja dengan:
- Menghasilkan HTML awal di server untuk semua komponen yang telah dirender sebelumnya yang merupakan bagian dari halaman yang sama.
- Membuat komponen interaktif pada klien setelah browser memuat kode yang dikompilasi aplikasi dan runtime .NET (jika belum dimuat) di latar belakang.
Jika komponen melemparkan pengecualian yang tidak tertangani selama pra-penyajian, misalnya, selama metode siklus hidup atau dalam logika penyajian:
- Dalam aplikasi yang Blazor beroperasi melalui sirkuit, pengecualiannya berakibat fatal bagi sirkuit. Untuk komponen sisi klien yang telah dirender sebelumnya, pengecualian mencegah penyajian komponen.
- Pengecualian dilemparkan ke tumpukan panggilan dari ComponentTagHelper.
Dalam keadaan normal saat pra-penyajian gagal, terus membangun dan merender komponen tidak masuk akal karena komponen yang berfungsi tidak dapat dirender.
Untuk mentolerir kesalahan yang mungkin terjadi selama pra-penyajian, logika penanganan kesalahan harus ditempatkan di dalam komponen yang dapat melemparkan pengecualian. Gunakan try-catch
pernyataan dengan penanganan kesalahan dan pengelogan. Alih-alih membungkus ComponentTagHelper dalam try-catch
pernyataan, tempatkan logika penanganan kesalahan dalam komponen yang dirender oleh ComponentTagHelper.
Skenario tingkat lanjut
Penyajian rekursif
Komponen dapat disarangkan secara rekursif. Ini berguna untuk mewakili struktur data rekursif. Misalnya, TreeNode
komponen dapat merender lebih TreeNode
banyak komponen untuk setiap anak simpul.
Saat merender secara rekursif, hindari pola pengkodian yang mengakibatkan rekursi tak terbatas:
- Jangan merender struktur data secara rekursif yang berisi siklus. Misalnya, jangan merender simpul pohon yang anak-anaknya menyertakan dirinya sendiri.
- Jangan membuat rantai tata letak yang berisi siklus. Misalnya, jangan membuat tata letak yang tata letaknya sendiri.
- Jangan izinkan pengguna akhir melanggar invarian rekursi (aturan) melalui entri data berbahaya atau panggilan interop JavaScript.
Perulangan tak terbatas selama penyajian:
- Menyebabkan proses penyajian berlanjut selamanya.
- Setara dengan membuat perulangan yang tidak ditentukan.
Dalam skenario ini, Blazor gagal dan biasanya mencoba untuk:
- Konsumsi waktu CPU sebanyak yang diizinkan oleh sistem operasi, tanpa batas waktu.
- Mengonsumsi memori dalam jumlah tak terbatas. Mengonsumsi memori tak terbatas setara dengan skenario di mana perulangan yang tidak ditentukan menambahkan entri ke koleksi pada setiap perulangan.
Untuk menghindari pola rekursi tak terbatas, pastikan bahwa kode rendering rekursif berisi kondisi penghentian yang sesuai.
Logika pohon render kustom
Sebagian besar Razor komponen diimplementasikan sebagai Razor file komponen (.razor
) dan dikompilasi oleh kerangka kerja untuk menghasilkan logika yang beroperasi pada RenderTreeBuilder untuk merender output mereka. Namun, pengembang dapat menerapkan logika secara RenderTreeBuilder manual menggunakan kode C# prosedural. Untuk informasi selengkapnya, lihat skenario lanjutan ASP.NET Core Blazor (konstruksi pohon render).
Peringatan
Penggunaan logika pembuat pohon render manual dianggap sebagai skenario tingkat lanjut dan tidak aman, tidak disarankan untuk pengembangan komponen umum.
Jika RenderTreeBuilder kode ditulis, pengembang harus menjamin kebenaran kode. Misalnya, pengembang harus memastikan bahwa:
- Panggilan ke OpenElement dan CloseElement diseimbangkan dengan benar.
- Atribut hanya ditambahkan di tempat yang benar.
Logika pembangun pohon render manual yang salah dapat menyebabkan perilaku tidak terdefinisi secara arbitrer, termasuk crash, aplikasi atau server berhenti merespons, dan kerentanan keamanan.
Pertimbangkan logika pembuat pohon render manual pada tingkat kompleksitas yang sama dan dengan tingkat bahaya yang sama seperti menulis kode perakitan atau instruksi Microsoft Intermediate Language (MSIL) secara manual.
Sumber Daya Tambahan:
†Aplikasi ke backend ASP.NET aplikasi API web Core yang digunakan aplikasi sisi Blazor klien untuk pengelogan.
ASP.NET Core