Bagikan melalui


manajemen status ASP.NET Core Blazor

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.

Artikel ini menjelaskan pendekatan umum untuk mempertahankan data pengguna (status) saat mereka menggunakan aplikasi dan di seluruh sesi browser.

Catatan

Contoh kode dalam artikel ini mengadopsi jenis referensi nullable (NRTs) dan .NET compiler null-state static analysis, yang didukung di ASP.NET Core di .NET 6 atau yang lebih baru. Saat menargetkan ASP.NET Core 5.0 atau yang lebih lama, hapus penunjukan jenis null (?) dari jenis dalam contoh artikel.

Pertahankan status pengguna

Sisi server Blazor adalah kerangka kerja aplikasi stateful. Sebagian besar waktu, aplikasi mempertahankan koneksi ke server. Status pengguna disimpan dalam memori server di sirkuit.

Contoh status pengguna yang disimpan di sirkuit meliputi:

  • Hierarki instans komponen dan output render terbarunya di UI yang dirender.
  • Nilai bidang dan properti dalam instans komponen.
  • Data yang disimpan dalam instans layanan injeksi dependensi (DI) yang tercakup ke sirkuit.

Status pengguna mungkin juga ditemukan dalam variabel JavaScript di set memori browser melalui panggilan interop JavaScript.

Jika pengguna mengalami kehilangan koneksi jaringan sementara, Blazor mencoba menyambungkan kembali pengguna ke sirkuit asli mereka dengan status aslinya. Namun, menyambungkan kembali pengguna ke sirkuit asli mereka dalam memori server tidak selalu memungkinkan:

  • Server tidak dapat mempertahankan sirkuit yang terputus selamanya. Server harus merilis sirkuit yang terputus setelah waktu habis atau ketika server berada di bawah tekanan memori.
  • Di lingkungan penyebaran multi-server, penyebaran yang seimbang beban, server individual mungkin gagal atau dihapus secara otomatis ketika tidak lagi diperlukan untuk menangani volume permintaan secara keseluruhan. Permintaan pemrosesan server asli untuk pengguna mungkin menjadi tidak tersedia ketika pengguna mencoba menyambungkan kembali.
  • Pengguna mungkin menutup dan membuka kembali browser mereka atau memuat ulang halaman, yang menghapus status apa pun yang disimpan di memori browser. Misalnya, nilai variabel JavaScript yang diatur melalui panggilan interop JavaScript hilang.

Ketika pengguna tidak dapat terhubung kembali ke sirkuit asli mereka, pengguna menerima sirkuit baru dengan status kosong. Ini setara dengan menutup dan membuka kembali aplikasi desktop.

Mempertahankan status di seluruh sirkuit

Umumnya, pertahankan status di seluruh sirkuit tempat pengguna secara aktif membuat data, bukan hanya membaca data yang sudah ada.

Untuk mempertahankan status di seluruh sirkuit, aplikasi harus menyimpan data ke beberapa lokasi penyimpanan lain daripada memori server. Persistensi status tidak otomatis. Anda harus mengambil langkah-langkah saat mengembangkan aplikasi untuk menerapkan persistensi data stateful.

Persistensi data biasanya hanya diperlukan untuk status bernilai tinggi yang dikeluarkan pengguna untuk dibuat. Dalam contoh berikut, status bertahan menghemat waktu atau membantu dalam aktivitas komersial:

  • Formulir web multi-langkah: Ini memakan waktu bagi pengguna untuk memasukkan kembali data untuk beberapa langkah lengkap formulir web multi-langkah jika statusnya hilang. Pengguna kehilangan status dalam skenario ini jika mereka menavigasi menjauh dari formulir dan kembali nanti.
  • Kelir belanja: Setiap komponen aplikasi yang penting secara komersial yang mewakili potensi pendapatan dapat dipertahankan. Pengguna yang kehilangan status mereka, dan dengan demikian kelir belanja mereka, dapat membeli lebih sedikit produk atau layanan ketika mereka kembali ke situs nanti.

Aplikasi hanya dapat mempertahankan status aplikasi. UI tidak dapat dipertahankan, seperti instans komponen dan pohon rendernya. Komponen dan pohon render umumnya tidak dapat diserialisasikan. Untuk mempertahankan status UI, seperti simpul kontrol tampilan pohon yang diperluas, aplikasi harus menggunakan kode kustom untuk memodelkan perilaku status UI sebagai status aplikasi yang dapat diserialisasikan.

Tempat untuk mempertahankan status

Lokasi umum ada untuk status bertahan:

Penyimpanan sisi server

Untuk persistensi data permanen yang mencakup beberapa pengguna dan perangkat, aplikasi dapat menggunakan penyimpanan sisi server. Opsi meliputi:

  • Penyimpanan Blob
  • Penyimpanan kunci-nilai
  • Database hubungan
  • Penyimpanan Tabel

Setelah data disimpan, status pengguna dipertahankan dan tersedia di sirkuit baru apa pun.

Untuk informasi selengkapnya tentang opsi penyimpanan data Azure, lihat yang berikut ini:

URL

Untuk data sementara yang mewakili status navigasi, modelkan data sebagai bagian dari URL. Contoh status pengguna yang dimodelkan dalam URL meliputi:

  • ID entitas yang dilihat.
  • Nomor halaman saat ini dalam kisi halaman.

Konten bilah alamat browser dipertahankan:

  • Jika pengguna memuat ulang halaman secara manual.
  • Jika server web menjadi tidak tersedia, dan pengguna dipaksa memuat ulang halaman untuk menyambungkan ke server lain.

Untuk informasi tentang menentukan pola URL dengan direktif@page, lihat perutean dan navigasi core Blazor ASP.NET.

Penyimpanan browser

Untuk data sementara yang dibuat pengguna secara aktif, lokasi penyimpanan yang umum digunakan adalah browser localStorage dan sessionStorage koleksi:

  • localStorage dilingkup ke jendela browser. Jika pengguna memuat ulang halaman atau menutup dan membuka kembali browser, status tetap ada. Jika pengguna membuka beberapa tab browser, status dibagikan di seluruh tab. Data bertahan hingga dihapus secara eksplisit localStorage .
  • sessionStorage dilingkup ke tab browser. Jika pengguna memuat ulang tab, status tetap ada. Jika pengguna menutup tab atau browser, status akan hilang. Jika pengguna membuka beberapa tab browser, setiap tab memiliki versi data independennya sendiri.

Umumnya, sessionStorage lebih aman digunakan. sessionStorage menghindari risiko pengguna membuka beberapa tab dan mengalami hal berikut:

  • Bug dalam penyimpanan status di seluruh tab.
  • Perilaku membingungkan saat tab menimpa status tab lain.

localStorage adalah pilihan yang lebih baik jika aplikasi harus mempertahankan status di seluruh penutupan dan membuka kembali browser.

Peringatan untuk menggunakan penyimpanan browser:

  • Mirip dengan penggunaan database sisi server, memuat dan menyimpan data bersifat asinkron.
  • Halaman yang diminta tidak ada di browser selama pra-penyajian, sehingga penyimpanan lokal tidak tersedia selama pra-penyajian.
  • Penyimpanan beberapa kilobyte data wajar untuk bertahan untuk aplikasi sisi Blazor server. Di luar beberapa kilobyte, Anda harus mempertimbangkan implikasi performa karena data dimuat dan disimpan di seluruh jaringan.
  • Pengguna dapat melihat atau mengubah data. ASP.NET Core Data Protection dapat mengurangi risiko. Misalnya, ASP.NET Core Protected Browser Storage menggunakan ASP.NET Core Data Protection.

Paket NuGet pihak ketiga menyediakan API untuk bekerja dengan localStorage dan sessionStorage. Ada baiknya mempertimbangkan untuk memilih paket yang secara transparan menggunakan ASP.NET Core Data Protection. Perlindungan Data mengenkripsi data yang disimpan dan mengurangi potensi risiko perubahan data yang disimpan. Jika data serial JSON disimpan dalam teks biasa, pengguna dapat melihat data menggunakan alat pengembang browser dan juga memodifikasi data yang disimpan. Mengamankan data sepele bukanlah masalah. Misalnya, membaca atau memodifikasi warna elemen UI yang disimpan bukanlah risiko keamanan yang signifikan bagi pengguna atau organisasi. Hindari mengizinkan pengguna memeriksa atau mengubah data sensitif.

ASP.NET Penyimpanan Browser yang Dilindungi Inti

ASP.NET Penyimpanan Browser Yang Dilindungi Inti memanfaatkan ASP.NET Perlindungan Data Inti untuk localStorage dan sessionStorage.

Catatan

Penyimpanan Browser yang Dilindungi bergantung pada ASP.NET Core Data Protection dan hanya didukung untuk aplikasi sisi Blazor server.

Peringatan

Microsoft.AspNetCore.ProtectedBrowserStorage adalah paket eksperimental yang tidak didukung yang tidak ditujukan untuk penggunaan produksi.

Paket ini hanya tersedia untuk digunakan di aplikasi ASP.NET Core 3.1.

Konfigurasi

  1. Tambahkan referensi paket ke Microsoft.AspNetCore.ProtectedBrowserStorage.

    Catatan

    Untuk panduan tentang menambahkan paket ke aplikasi .NET, lihat artikel di bagian Menginstal dan mengelola paket di Alur kerja konsumsi paket (dokumentasi NuGet). Konfirmasikan versi paket yang benar di NuGet.org.

  2. _Host.cshtml Dalam file, tambahkan skrip berikut di dalam tag penutup</body>:

    <script src="_content/Microsoft.AspNetCore.ProtectedBrowserStorage/protectedBrowserStorage.js"></script>
    
  3. Di Startup.ConfigureServices, panggil AddProtectedBrowserStorage untuk menambahkan localStorage dan sessionStorage layanan ke kumpulan layanan:

    services.AddProtectedBrowserStorage();
    

Menyimpan dan memuat data dalam komponen

Dalam komponen apa pun yang memerlukan pemuatan atau penyimpanan data ke penyimpanan browser, gunakan direktif @inject untuk menyuntikkan instans dari salah satu hal berikut:

  • ProtectedLocalStorage
  • ProtectedSessionStorage

Pilihan tergantung pada lokasi penyimpanan browser mana yang ingin Anda gunakan. Dalam contoh berikut, sessionStorage digunakan:

@using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage
@inject ProtectedSessionStorage ProtectedSessionStore
@using Microsoft.AspNetCore.ProtectedBrowserStorage
@inject ProtectedSessionStorage ProtectedSessionStore

Arahan @using dapat ditempatkan dalam file aplikasi _Imports.razor alih-alih di komponen. Penggunaan _Imports.razor file membuat namespace layanan tersedia untuk segmen aplikasi yang lebih besar atau seluruh aplikasi.

Untuk mempertahankan nilai dalam Counter komponen aplikasi berdasarkan Blazor templat proyek, ubah IncrementCount metode untuk menggunakan ProtectedSessionStore.SetAsync:currentCount

private async Task IncrementCount()
{
    currentCount++;
    await ProtectedSessionStore.SetAsync("count", currentCount);
}

Dalam aplikasi yang lebih besar dan lebih realistis, penyimpanan bidang individual adalah skenario yang tidak mungkin. Aplikasi lebih cenderung menyimpan seluruh objek model yang menyertakan status kompleks. ProtectedSessionStore secara otomatis menserialisasikan dan mendeserialisasi data JSON untuk menyimpan objek status yang kompleks.

Dalam contoh kode sebelumnya, currentCount data disimpan seperti sessionStorage['count'] di browser pengguna. Data tidak disimpan dalam teks biasa melainkan dilindungi menggunakan ASP.NET Core Data Protection. Data terenkripsi dapat diperiksa jika sessionStorage['count'] dievaluasi di konsol pengembang browser.

Untuk memulihkan currentCount data jika pengguna kembali ke Counter komponen nanti, termasuk jika pengguna berada di sirkuit baru, gunakan ProtectedSessionStore.GetAsync:

protected override async Task OnInitializedAsync()
{
    var result = await ProtectedSessionStore.GetAsync<int>("count");
    currentCount = result.Success ? result.Value : 0;
}
protected override async Task OnInitializedAsync()
{
    currentCount = await ProtectedSessionStore.GetAsync<int>("count");
}

Jika parameter komponen menyertakan status navigasi, panggil ProtectedSessionStore.GetAsync dan tetapkan non-hasilnull di OnParametersSetAsync, bukan OnInitializedAsync. OnInitializedAsync hanya dipanggil sekali ketika komponen pertama kali dibuat. OnInitializedAsync tidak dipanggil lagi nanti jika pengguna menavigasi ke URL lain saat tetap berada di halaman yang sama. Untuk informasi lebih lanjut, lihat siklus hidup komponen Razor ASP.NET Core.

Peringatan

Contoh di bagian ini hanya berfungsi jika server tidak mengaktifkan pra-penyajian. Dengan prerendering diaktifkan, kesalahan dihasilkan menjelaskan bahwa panggilan interop JavaScript tidak dapat dikeluarkan karena komponen sedang dirender.

Nonaktifkan pra-penyajian atau tambahkan kode tambahan untuk bekerja dengan pra-penyajian. Untuk mempelajari selengkapnya tentang menulis kode yang berfungsi dengan pra-penyajian, lihat bagian Menangani pra-penyajian .

Menangani status pemuatan

Karena penyimpanan browser diakses secara asinkron melalui koneksi jaringan, selalu ada periode waktu sebelum data dimuat dan tersedia untuk komponen. Untuk hasil terbaik, render pesan saat pemuatan sedang berlangsung alih-alih menampilkan data kosong atau default.

Salah satu pendekatannya adalah melacak apakah data tersebut , nullyang berarti bahwa data masih dimuat. Dalam komponen default Counter , hitungan disimpan dalam int. Buat currentCount nullable dengan menambahkan tanda tanya (?) ke jenis (int):

private int? currentCount;

Alih-alih menampilkan jumlah dan Increment tombol secara tanpa syarat, tampilkan elemen-elemen ini hanya jika data dimuat dengan memeriksa HasValue:

@if (currentCount.HasValue)
{
    <p>Current count: <strong>@currentCount</strong></p>
    <button @onclick="IncrementCount">Increment</button>
}
else
{
    <p>Loading...</p>
}

Menangani pra-penyajian

Selama pra-penyajian:

  • Koneksi interaktif ke browser pengguna tidak ada.
  • Browser belum memiliki halaman tempat browser dapat menjalankan kode JavaScript.

localStorage atau sessionStorage tidak tersedia selama pra-penyajian. Jika komponen mencoba berinteraksi dengan penyimpanan, kesalahan dihasilkan menjelaskan bahwa panggilan interop JavaScript tidak dapat dikeluarkan karena komponen sedang dirender.

Salah satu cara untuk mengatasi kesalahan adalah dengan menonaktifkan pra-penyajian. Ini biasanya merupakan pilihan terbaik jika aplikasi menggunakan penyimpanan berbasis browser dengan berat. Pra-penyajian menambah kompleksitas dan tidak menguntungkan aplikasi karena aplikasi tidak dapat merender konten yang berguna hingga localStorage atau sessionStorage tersedia.

Untuk menonaktifkan pra-penyajian, tunjukkan mode render dengan parameter yang prerender diatur ke false pada komponen tingkat tertinggi dalam hierarki komponen aplikasi yang bukan komponen root.

Catatan

Membuat komponen akar interaktif, seperti App komponen, tidak didukung. Oleh karena itu, pra-penyajian tidak dapat dinonaktifkan secara langsung oleh App komponen.

Untuk aplikasi berdasarkan Blazor Web App templat proyek, pra-penyajian biasanya dinonaktifkan di mana Routes komponen digunakan dalam App komponen (Components/App.razor):

<Routes @rendermode="new InteractiveServerRenderMode(prerender: false)" />

Selain itu, nonaktifkan pra-penyajian HeadOutlet untuk komponen:

<HeadOutlet @rendermode="new InteractiveServerRenderMode(prerender: false)" />

Untuk informasi selengkapnya, lihat mode render ASP.NET CoreBlazor.

Untuk menonaktifkan pra-penyajian_Host.cshtml, buka file dan ubah render-mode atribut Pembantu Tag Komponen menjadi Server:

<component type="typeof(App)" render-mode="Server" />

Saat pra-penyajian dinonaktifkan, pra-penyajian <head> konten dinonaktifkan.

Pra-penyajian mungkin berguna untuk halaman lain yang tidak menggunakan localStorage atau sessionStorage. Untuk mempertahankan pra-penyajian, tangguhkan operasi pemuatan hingga browser terhubung ke sirkuit. Berikut ini adalah contoh untuk menyimpan nilai penghitung:

@using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage
@inject ProtectedLocalStorage ProtectedLocalStore

@if (isConnected)
{
    <p>Current count: <strong>@currentCount</strong></p>
    <button @onclick="IncrementCount">Increment</button>
}
else
{
    <p>Loading...</p>
}

@code {
    private int currentCount;
    private bool isConnected;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            isConnected = true;
            await LoadStateAsync();
            StateHasChanged();
        }
    }

    private async Task LoadStateAsync()
    {
        var result = await ProtectedLocalStore.GetAsync<int>("count");
        currentCount = result.Success ? result.Value : 0;
    }

    private async Task IncrementCount()
    {
        currentCount++;
        await ProtectedLocalStore.SetAsync("count", currentCount);
    }
}
@using Microsoft.AspNetCore.ProtectedBrowserStorage
@inject ProtectedLocalStorage ProtectedLocalStore

@if (isConnected)
{
    <p>Current count: <strong>@currentCount</strong></p>
    <button @onclick="IncrementCount">Increment</button>
}
else
{
    <p>Loading...</p>
}

@code {
    private int currentCount = 0;
    private bool isConnected = false;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            isConnected = true;
            await LoadStateAsync();
            StateHasChanged();
        }
    }

    private async Task LoadStateAsync()
    {
        currentCount = await ProtectedLocalStore.GetAsync<int>("count");
    }

    private async Task IncrementCount()
    {
        currentCount++;
        await ProtectedLocalStore.SetAsync("count", currentCount);
    }
}

Memperhitungkan pelestarian status ke lokasi umum

Jika banyak komponen mengandalkan penyimpanan berbasis browser, menerapkan kode penyedia status berkali-kali membuat duplikasi kode. Salah satu opsi untuk menghindari duplikasi kode adalah membuat komponen induk penyedia status yang merangkum logika penyedia status. Komponen anak dapat bekerja dengan data yang bertahan tanpa memperhatikan mekanisme kegigihan status.

Dalam contoh CounterStateProvider komponen berikut, data penghitung dipertahankan ke sessionStorage:

@using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage
@inject ProtectedSessionStorage ProtectedSessionStore

@if (isLoaded)
{
    <CascadingValue Value="this">
        @ChildContent
    </CascadingValue>
}
else
{
    <p>Loading...</p>
}

@code {
    private bool isLoaded;

    [Parameter]
    public RenderFragment? ChildContent { get; set; }

    public int CurrentCount { get; set; }

    protected override async Task OnInitializedAsync()
    {
        var result = await ProtectedSessionStore.GetAsync<int>("count");
        CurrentCount = result.Success ? result.Value : 0;
        isLoaded = true;
    }

    public async Task SaveChangesAsync()
    {
        await ProtectedSessionStore.SetAsync("count", CurrentCount);
    }
}
@using Microsoft.AspNetCore.ProtectedBrowserStorage
@inject ProtectedSessionStorage ProtectedSessionStore

@if (isLoaded)
{
    <CascadingValue Value="this">
        @ChildContent
    </CascadingValue>
}
else
{
    <p>Loading...</p>
}

@code {
    private bool isLoaded;

    [Parameter]
    public RenderFragment ChildContent { get; set; }

    public int CurrentCount { get; set; }

    protected override async Task OnInitializedAsync()
    {
        CurrentCount = await ProtectedSessionStore.GetAsync<int>("count");
        isLoaded = true;
    }

    public async Task SaveChangesAsync()
    {
        await ProtectedSessionStore.SetAsync("count", CurrentCount);
    }
}

Catatan

Untuk informasi selengkapnya tentang RenderFragment, lihat komponen ASP.NET CoreRazor.

Komponen CounterStateProvider menangani fase pemuatan dengan tidak merender konten turunannya hingga pemuatan status selesai.

Untuk membuat status dapat diakses oleh semua komponen dalam aplikasi, bungkus CounterStateProvider komponen di sekitar Router (<Router>...</Router>) dalam Routes komponen dengan penyajian sisi server interaktif global (SSR interaktif).

Dalam komponen App (Components/App.razor):

<Routes @rendermode="InteractiveServer" />

Dalam komponen Routes (Components/Routes.razor):

Untuk menggunakan CounterStateProvider komponen, bungkus instans komponen di sekitar komponen lain yang memerlukan akses ke status penghitung. Untuk membuat status dapat diakses oleh semua komponen dalam aplikasi, bungkus CounterStateProvider komponen di App sekitar Router komponen (App.razor):

<CounterStateProvider>
    <Router ...>
        ...
    </Router>
</CounterStateProvider>

Catatan

Dengan rilis ASP.NET Core 5.0.1 dan untuk rilis 5.x tambahan, komponen Router menyertakan parameter PreferExactMatches yang diatur ke @true. Untuk informasi lebih lanjut, lihat Migrasi dari ASP.NET Core 3.1 ke 5.0.

Komponen yang dibungkus menerima dan dapat memodifikasi status penghitung yang bertahan. Komponen berikut Counter mengimplementasikan pola:

@page "/counter"

<p>Current count: <strong>@CounterStateProvider?.CurrentCount</strong></p>
<button @onclick="IncrementCount">Increment</button>

@code {
    [CascadingParameter]
    private CounterStateProvider? CounterStateProvider { get; set; }

    private async Task IncrementCount()
    {
        if (CounterStateProvider is not null)
        {
            CounterStateProvider.CurrentCount++;
            await CounterStateProvider.SaveChangesAsync();
        }
    }
}

Komponen sebelumnya tidak diperlukan untuk berinteraksi dengan ProtectedBrowserStorage, juga tidak berurusan dengan fase "pemuatan".

Untuk menangani pra-penyajian seperti yang dijelaskan sebelumnya, CounterStateProvider dapat diubah sehingga semua komponen yang mengonsumsi data penghitung secara otomatis bekerja dengan pra-penyajian. Untuk informasi selengkapnya, lihat bagian Menangani pra-penyajian .

Secara umum, pola komponen induk penyedia status direkomendasikan:

  • Untuk mengonsumsi status di banyak komponen.
  • Jika hanya ada satu objek status tingkat atas yang akan dipertahankan.

Untuk mempertahankan banyak objek status yang berbeda dan mengonsumsi subset objek yang berbeda di tempat yang berbeda, lebih baik menghindari status bertahan secara global.

Status pengguna yang Blazor WebAssembly dibuat di aplikasi disimpan di memori browser.

Contoh status pengguna yang disimpan dalam memori browser meliputi:

Saat pengguna menutup dan membuka kembali browser mereka atau memuat ulang halaman, status pengguna yang disimpan di memori browser hilang.

Catatan

Penyimpanan Browser Terproteksi (Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage namespace) bergantung pada ASP.NET Core Data Protection dan hanya didukung untuk aplikasi sisi Blazor server.

Mempertahankan status di seluruh sesi browser

Umumnya, pertahankan status di seluruh sesi browser di mana pengguna secara aktif membuat data, bukan hanya membaca data yang sudah ada.

Untuk mempertahankan status di seluruh sesi browser, aplikasi harus menyimpan data ke beberapa lokasi penyimpanan lain daripada memori browser. Persistensi status tidak otomatis. Anda harus mengambil langkah-langkah saat mengembangkan aplikasi untuk menerapkan persistensi data stateful.

Persistensi data biasanya hanya diperlukan untuk status bernilai tinggi yang dikeluarkan pengguna untuk dibuat. Dalam contoh berikut, status bertahan menghemat waktu atau membantu dalam aktivitas komersial:

  • Formulir web multi-langkah: Ini memakan waktu bagi pengguna untuk memasukkan kembali data untuk beberapa langkah lengkap formulir web multi-langkah jika statusnya hilang. Pengguna kehilangan status dalam skenario ini jika mereka menavigasi menjauh dari formulir dan kembali nanti.
  • Kelir belanja: Setiap komponen aplikasi yang penting secara komersial yang mewakili potensi pendapatan dapat dipertahankan. Pengguna yang kehilangan status mereka, dan dengan demikian kelir belanja mereka, dapat membeli lebih sedikit produk atau layanan ketika mereka kembali ke situs nanti.

Aplikasi hanya dapat mempertahankan status aplikasi. UI tidak dapat dipertahankan, seperti instans komponen dan pohon rendernya. Komponen dan pohon render umumnya tidak dapat diserialisasikan. Untuk mempertahankan status UI, seperti simpul kontrol tampilan pohon yang diperluas, aplikasi harus menggunakan kode kustom untuk memodelkan perilaku status UI sebagai status aplikasi yang dapat diserialisasikan.

Tempat untuk mempertahankan status

Lokasi umum ada untuk status bertahan:

Penyimpanan sisi server

Untuk persistensi data permanen yang mencakup beberapa pengguna dan perangkat, aplikasi dapat menggunakan penyimpanan sisi server independen yang diakses melalui API web. Opsi meliputi:

  • Penyimpanan Blob
  • Penyimpanan kunci-nilai
  • Database hubungan
  • Penyimpanan Tabel

Setelah data disimpan, status pengguna dipertahankan dan tersedia di sesi browser baru apa pun.

Karena Blazor WebAssembly aplikasi berjalan sepenuhnya di browser pengguna, aplikasi memerlukan langkah-langkah tambahan untuk mengakses sistem eksternal yang aman, seperti layanan penyimpanan dan database. Aplikasi Blazor WebAssembly diamankan dengan cara yang sama seperti aplikasi satu halaman (SPA). Biasanya, aplikasi mengautentikasi pengguna melalui OAuth/OpenID Connect (OIDC) lalu berinteraksi dengan layanan penyimpanan dan database melalui panggilan API web ke aplikasi sisi server. Aplikasi sisi server menengahi transfer data antara Blazor WebAssembly aplikasi dan layanan penyimpanan atau database. Aplikasi ini Blazor WebAssembly mempertahankan koneksi sementara ke aplikasi sisi server, sementara aplikasi sisi server memiliki koneksi persisten ke penyimpanan.

Untuk informasi selengkapnya, lihat sumber daya berikut:

Untuk informasi selengkapnya tentang opsi penyimpanan data Azure, lihat yang berikut ini:

URL

Untuk data sementara yang mewakili status navigasi, modelkan data sebagai bagian dari URL. Contoh status pengguna yang dimodelkan dalam URL meliputi:

  • ID entitas yang dilihat.
  • Nomor halaman saat ini dalam kisi halaman.

Konten bilah alamat browser dipertahankan jika pengguna memuat ulang halaman secara manual.

Untuk informasi tentang menentukan pola URL dengan direktif@page, lihat perutean dan navigasi core Blazor ASP.NET.

Penyimpanan browser

Untuk data sementara yang dibuat pengguna secara aktif, lokasi penyimpanan yang umum digunakan adalah browser localStorage dan sessionStorage koleksi:

  • localStorage dilingkup ke jendela browser. Jika pengguna memuat ulang halaman atau menutup dan membuka kembali browser, status tetap ada. Jika pengguna membuka beberapa tab browser, status dibagikan di seluruh tab. Data bertahan hingga dihapus secara eksplisit localStorage .
  • sessionStorage dilingkup ke tab browser. Jika pengguna memuat ulang tab, status tetap ada. Jika pengguna menutup tab atau browser, status akan hilang. Jika pengguna membuka beberapa tab browser, setiap tab memiliki versi data independennya sendiri.

Catatan

localStorage dan sessionStorage dapat digunakan di Blazor WebAssembly aplikasi tetapi hanya dengan menulis kode kustom atau menggunakan paket pihak ketiga.

Umumnya, sessionStorage lebih aman digunakan. sessionStorage menghindari risiko pengguna membuka beberapa tab dan mengalami hal berikut:

  • Bug dalam penyimpanan status di seluruh tab.
  • Perilaku membingungkan saat tab menimpa status tab lain.

localStorage adalah pilihan yang lebih baik jika aplikasi harus mempertahankan status di seluruh penutupan dan membuka kembali browser.

Peringatan

Pengguna dapat melihat atau mengubah data yang disimpan di localStorage dan sessionStorage.

Layanan kontainer status dalam memori

Komponen berlapis biasanya mengikat data menggunakan ikatan berantai seperti yang dijelaskan dalam pengikatan data ASP.NET CoreBlazor. Komponen berlapis dan tidak terencana dapat berbagi akses ke data menggunakan kontainer status dalam memori terdaftar. Kelas kontainer status kustom dapat menggunakan yang dapat Action ditetapkan untuk memberi tahu komponen di berbagai bagian aplikasi perubahan status. Dalam contoh berikut:

  • Sepasang komponen menggunakan kontainer status untuk melacak properti.
  • Satu komponen dalam contoh berikut disarangkan di komponen lain, tetapi bersarang tidak diperlukan agar pendekatan ini berfungsi.

Penting

Contoh di bagian ini menunjukkan cara membuat layanan kontainer status dalam memori, mendaftarkan layanan, dan menggunakan layanan dalam komponen. Contohnya tidak menyimpan data tanpa pengembangan lebih lanjut. Untuk penyimpanan data persisten, kontainer status harus mengadopsi mekanisme penyimpanan yang mendasar yang bertahan ketika memori browser dihapus. Ini dapat dicapai dengan localStorage/sessionStorage atau beberapa teknologi lainnya.

StateContainer.cs:

public class StateContainer
{
    private string? savedString;

    public string Property
    {
        get => savedString ?? string.Empty;
        set
        {
            savedString = value;
            NotifyStateChanged();
        }
    }

    public event Action? OnChange;

    private void NotifyStateChanged() => OnChange?.Invoke();
}

Aplikasi sisi klien (Program file):

builder.Services.AddSingleton<StateContainer>();

Aplikasi sisi server (Program file, ASP.NET Core di .NET 6 atau yang lebih baru):

builder.Services.AddScoped<StateContainer>();

Aplikasi sisi server (Startup.ConfigureServices dari Startup.cs, ASP.NET Core lebih awal dari 6.0):

services.AddScoped<StateContainer>();

Shared/Nested.razor:

@implements IDisposable
@inject StateContainer StateContainer

<h2>Nested component</h2>

<p>Nested component Property: <b>@StateContainer.Property</b></p>

<p>
    <button @onclick="ChangePropertyValue">
        Change the Property from the Nested component
    </button>
</p>

@code {
    protected override void OnInitialized()
    {
        StateContainer.OnChange += StateHasChanged;
    }

    private void ChangePropertyValue()
    {
        StateContainer.Property = 
            $"New value set in the Nested component: {DateTime.Now}";
    }

    public void Dispose()
    {
        StateContainer.OnChange -= StateHasChanged;
    }
}

StateContainerExample.razor:

@page "/state-container-example"
@implements IDisposable
@inject StateContainer StateContainer

<h1>State Container Example component</h1>

<p>State Container component Property: <b>@StateContainer.Property</b></p>

<p>
    <button @onclick="ChangePropertyValue">
        Change the Property from the State Container Example component
    </button>
</p>

<Nested />

@code {
    protected override void OnInitialized()
    {
        StateContainer.OnChange += StateHasChanged;
    }

    private void ChangePropertyValue()
    {
        StateContainer.Property = "New value set in the State " +
            $"Container Example component: {DateTime.Now}";
    }

    public void Dispose()
    {
        StateContainer.OnChange -= StateHasChanged;
    }
}

Komponen sebelumnya mengimplementasikan IDisposable, dan OnChange delegasi tidak berlangganan dalam Dispose metode, yang dipanggil oleh kerangka kerja ketika komponen dibuang. Untuk informasi lebih lanjut, lihat siklus hidup komponen Razor ASP.NET Core.

Pendekatan tambahan

Saat menerapkan penyimpanan status kustom, pendekatan yang berguna adalah mengadopsi nilai dan parameter berskala:

  • Untuk mengonsumsi status di banyak komponen.
  • Jika hanya ada satu objek status tingkat atas yang akan dipertahankan.

Pecahkan masalah

Dalam layanan manajemen status kustom, panggilan balik yang dipanggil di luar Blazorkonteks sinkronisasi harus membungkus logika panggilan balik ComponentBase.InvokeAsync untuk memindahkannya ke konteks sinkronisasi perender.

Saat layanan manajemen status tidak memanggil StateHasChanged Blazorkonteks sinkronisasi 's, kesalahan berikut akan muncul:

System.InvalidOperationException: 'Utas saat ini tidak terkait dengan Dispatcher. Gunakan InvokeAsync() untuk mengalihkan eksekusi ke Dispatcher saat memicu penyajian atau status komponen.'

Untuk informasi selengkapnya dan contoh cara mengatasi kesalahan ini, lihat ASP.NET penyajian komponen CoreRazor.

Sumber Daya Tambahan: