Browser Storage
Storing something in the browser to access it easier & frequently with less load time.
Here is a very interesting article on how to store Encrypted Session Data in the browser.
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
Implementation
Workflow
- We are having weather.json in wwwroot folder, so consider this as response.
- Now we want to store that JSON response in browser as cache and access it with our code.
- We are going to do the following basic operation like store, get, remove, delete with cache data
Step 1 - Base code setup
Have following files in following path as shown below
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 !!! ***
Check out Blazor on C# Corner to learn more about Blazor.