Browser Storage
Storing something in the browser to access it easier & frequently with less load time.

Types of browser storage

There are 6 types of browser storage:

  • Cache
  • Cookie
  • Indexed DB
  • Local storage
  • Memory
  • Session storage

Compare browser storage types

  Its Lifetime Allowed data type Shared between browser tabs
Cache Until deleted Request, Response YES
Cookie Expired time / until deleted Key value YES
Indexed DB Until deleted Various types YES
Local storage Until deleted Key value YES
Memory Users exist/ close browser tab Various types NO
Session storage Users exist/ close browser tab Key value NO

In this article, we are going to see about cache storage and how to implement this in Blazor WASM using JavaScript.

Cache Storage
Store any request/responses as cache in browser to speed up the loading process.

Benefits

  • Improves performance
  • Reduce call to servers
  • Provide offline data support

Step 2
Create razor page named CacheStorage.razor and add following code to activate cache storage and its operations
@page "/cache"
@inject MyBlazorWasmApp.Helper.CacheStorageAccessor CacheStorageAccessor
@inject HttpClient HttpClient
<h3>CacheStorage</h3>
<hr />
<button class="btn btn-primary" type="button" @onclick="SetValueAsync">Set Value</button>
<div>Stored Value: @StoredValue</div>
<button class="btn btn-primary" type="button" @onclick="GetValueAsync">Get Value</button>
<button class="btn btn-primary" type="button" @onclick="RemoveAsync">Remove Value</button>
<button class="btn btn-primary" type="button" @onclick="ClearAllAsync">Clear All</button>
@code {
    public string StoredValue { get; set; } = "";
    public async Task SetValueAsync()
    {
        var message = CreateMessage();
        var response = await HttpClient.SendAsync(message);
        await CacheStorageAccessor.StoreAsync(message, response);
    }
    public async Task GetValueAsync()
    {
        StoredValue = await CacheStorageAccessor.GetAsync(CreateMessage());
    }
    public async Task RemoveAsync()
    {
        await CacheStorageAccessor.RemoveAsync(CreateMessage());
    }
    public async Task ClearAllAsync()
    {
        await CacheStorageAccessor.RemoveAllAsync();
    }
    public HttpRequestMessage CreateMessage() => new HttpRequestMessage(HttpMethod.Get, "/sample-data/weather.json");
}

The razor page will call respective JavaScript function to process cache

Step 3
Setup JavaScript file with below code
async function openCacheStorage() {
    return await window.caches.open("Kajul - Blazor App");
}

function createRequest(url, method, body = "") {
    let requestInit = {
        method: method
    };
    if (body != "") {
        requestInit.body = body;
    }
    let request = new Request(url, requestInit);
    console.log(request);
    return request;
}
//In your JavaScript module, add functions to store, get, delete the data:
export async function store(url, method, body = "", responseString) {
    let kajulBlazorCache = await openCacheStorage();
    let request = createRequest(url, method, body);
    let response = new Response(responseString);
    await kajulBlazorCache.put(request, response);
}
export async function get(url, method, body = "") {
    let kajulBlazorCache = await openCacheStorage();
    let request = createRequest(url, method, body);
    let response = await kajulBlazorCache.match(request);
    if (response == undefined) {
        return "";
    }
    let result = await response.text();
    return result;
}
export async function remove(url, method, body = "") {
    let kajulBlazorCache = await openCacheStorage();
    let request = createRequest(url, method, body);
    await kajulBlazorCache.delete(request);
}
export async function removeAll() {
    let kajulBlazorCache = await openCacheStorage();
    let requests = await kajulBlazorCache.keys();
    for (let i = 0; i < requests.length; i++) {
        await kajulBlazorCache.delete(requests[i]);
    }
}

Step 4
Create a helper class (CacheStorageAccessor.cs) to connect razor and JavaScript functions
using Microsoft.JSInterop;
namespace MyBlazorWasmApp.Helper;
public class CacheStorageAccessor: IAsyncDisposable {
    private Lazy < IJSObjectReference > _accessorJsRef = new();
    private readonly IJSRuntime _jsRuntime;
    //constructor
    public CacheStorageAccessor(IJSRuntime jsRuntime) {
        _jsRuntime = jsRuntime;
    }
    //Common method - You will need to call WaitForReference() in all methods.
    private async Task WaitForReference() {
        if (_accessorJsRef.IsValueCreated is false) {
            _accessorJsRef = new(await _jsRuntime.InvokeAsync < IJSObjectReference > ("import", "/js/CacheStorageAccessor.js"));
        }
    }
    //Always remember to dispose the JavaScript module.
    public async ValueTask DisposeAsync() {
        if (_accessorJsRef.IsValueCreated) {
            await _accessorJsRef.Value.DisposeAsync();
        }
    }
    #region create a new method
    for each operation
    //the below is C# blazor methods will link the js functions respective to its name
    public async Task StoreAsync(HttpRequestMessage requestMessage, HttpResponseMessage responseMessage) {
        await WaitForReference();
        string requestMethod = requestMessage.Method.Method;
        string requestBody = await GetRequestBodyAsync(requestMessage);
        string responseBody = await responseMessage.Content.ReadAsStringAsync();
        await _accessorJsRef.Value.InvokeVoidAsync("store", requestMessage.RequestUri, requestMethod, requestBody, responseBody);
    }
    public async Task < string > GetAsync(HttpRequestMessage requestMessage) {
        await WaitForReference();
        string requestMethod = requestMessage.Method.Method;
        string requestBody = await GetRequestBodyAsync(requestMessage);
        string result = await _accessorJsRef.Value.InvokeAsync < string > ("get", requestMessage.RequestUri, requestMethod, requestBody);
        return result;
    }
    public async Task RemoveAsync(HttpRequestMessage requestMessage) {
        await WaitForReference();
        string requestMethod = requestMessage.Method.Method;
        string requestBody = await GetRequestBodyAsync(requestMessage);
        await _accessorJsRef.Value.InvokeVoidAsync("remove", requestMessage.RequestUri, requestMethod, requestBody);
    }
    public async Task RemoveAllAsync() {
        await WaitForReference();
        await _accessorJsRef.Value.InvokeVoidAsync("removeAll");
    }
    private static async Task < string > GetRequestBodyAsync(HttpRequestMessage requestMessage) {
        string requestBody = "";
        if (requestMessage.Content is not null) {
            requestBody = await requestMessage.Content.ReadAsStringAsync() ?? "";
        }
        return requestBody;
    }
    #endregion
}


Step 5
Register the helper class in Program.cs
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using MyBlazorWasmApp;
using MyBlazorWasmApp.Helper;
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add < App > ("#app");
builder.RootComponents.Add < HeadOutlet > ("head::after");
//Register helper class
builder.Services.AddScoped < CacheStorageAccessor > ();
builder.Services.AddScoped(sp => new HttpClient {
    BaseAddress = new Uri(builder.HostEnvironment.BaseAddress)
});
await builder.Build().RunAsync();


Step 6: Run to See output in browser
Output for blazar wasm cache storage using js

Happy Coding!