Local Storage Utility (Cookies) for Blazor WebAssembly App
Here is a local storage utility that relies on dependency injection which means a line of code must be added to the Program.cs file in the Blazor client/WebAssembly app.
Here is one example of using the LocalStorage utility to store an array of strings:
@page "/localstorage"
@inject Utilities.ILocalStorage LocalStorage
<h3>Local Storage</h3>
<div>
@if (data != null)
{
foreach (var s in data)
{
<p>@s</p>
}
}
</div>
@code {
string[] data;
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
string[] values = new[] { "token", "username", "email", DateTime.Now.ToString() };
// save array of user data
await LocalStorage.SaveStringArrayAsync("user", values); // could also use SaveObjectAsync()
// retrieve array of user data
data = await LocalStorage.GetStringArrayAsync("user"); // could also use GetObjectAsync()
// delete user data
await LocalStorage.RemoveAsync("user");
}
}
Here is another example of using the LocalStorage utility to store an object:
@page "/localstorage"
@inject Utilities.ILocalStorage LocalStorage
<h3>Local Storage Example</h3>
<div>
@if (data != null)
{
<p>@data.username</p>
<p>@data.email</p>
<p>@data.jwt</p>
<p>@data.created</p>
}
</div>
@code {
User data;
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
User value = new User { username = "username",
email = "email@gmail.com",
jwt = "fhasu9f3whfi8fdakid",
created = DateTime.Now };
await LocalStorage.SaveObjectAsync("user", value);
data = (User)await LocalStorage.GetObjectAsync("user");
await LocalStorage.RemoveAsync("user");
}
}
// User.cs
using System;
namespace BlazorExample.Shared
{
[Serializable]
public class User
{
public string username;
public string email;
public string jwt;
public DateTime created;
}
}
Here is the code for the LocalStorage utility. It relies on no libraries other than those which are included with Blazor WebAssembly.
// LocalStorage.cs
using System.Threading.Tasks;
using Microsoft.JSInterop;
namespace Utilities
{
public interface ILocalStorage
{
/// <summary>
/// Remove a key from browser local storage.
/// </summary>
/// <param name="key">The key previously used to save to local storage.</param>
public Task RemoveAsync(string key);
/// <summary>
/// Save a string value to browser local storage.
/// </summary>
/// <param name="key">The key to use to save to and retrieve from local storage.</param>
/// <param name="value">The string value to save to local storage.</param>
public Task SaveStringAsync(string key, string value);
/// <summary>
/// Get a string value from browser local storage.
/// </summary>
/// <param name="key">The key previously used to save to local storage.</param>
/// <returns>The string previously saved to local storage.</returns>
public Task<string> GetStringAsync(string key);
/// <summary>
/// Save an array of string values to browser local storage.
/// </summary>
/// <param name="key">The key previously used to save to local storage.</param>
/// <param name="values">The array of string values to save to local storage.</param>
public Task SaveStringArrayAsync(string key, string[] values);
/// <summary>
/// Get an array of string values from browser local storage.
/// </summary>
/// <param name="key">The key previously used to save to local storage.</param>
/// <returns>The array of string values previously saved to local storage.</returns>
public Task<string[]> GetStringArrayAsync(string key);
/// <summary>
/// Save an object value to browser local storage.
/// </summary>
/// <param name="key">The key to use to save to and retrieve from local storage.</param>
/// <param name="value">The object to save to local storage.</param>
public Task SaveObjectAsync(string key, object value);
/// <summary>
/// Get an object from browser local storage.
/// </summary>
/// <param name="key">The key previously used to save to local storage.</param>
/// <returns>The object previously saved to local storage.</returns>
public Task<object> GetObjectAsync(string key);
}
public class LocalStorage : ILocalStorage
{
private readonly IJSRuntime jsruntime;
public LocalStorage(IJSRuntime jSRuntime)
{
jsruntime = jSRuntime;
}
/// <summary>
/// Remove a key from browser local storage.
/// </summary>
/// <param name="key">The key previously used to save to local storage.</param>
public async Task RemoveAsync(string key)
{
await jsruntime.InvokeVoidAsync("localStorage.removeItem", key).ConfigureAwait(false);
}
/// <summary>
/// Save a string value to browser local storage.
/// </summary>
/// <param name="key">The key to use to save to and retrieve from local storage.</param>
/// <param name="value">The string value to save to local storage.</param>
public async Task SaveStringAsync(string key, string value)
{
await jsruntime.InvokeVoidAsync("localStorage.setItem", key, value).ConfigureAwait(false);
}
/// <summary>
/// Get a string value from browser local storage.
/// </summary>
/// <param name="key">The key previously used to save to local storage.</param>
/// <returns>The string previously saved to local storage.</returns>
public async Task<string> GetStringAsync(string key)
{
return await jsruntime.InvokeAsync<string>("localStorage.getItem", key).ConfigureAwait(false);
}
/// <summary>
/// Save an array of string values to browser local storage.
/// </summary>
/// <param name="key">The key previously used to save to local storage.</param>
/// <param name="values">The array of string values to save to local storage.</param>
public async Task SaveStringArrayAsync(string key, string[] values)
{
if (values != null)
await jsruntime.InvokeVoidAsync("localStorage.setItem", key, string.Join('\0', values)).ConfigureAwait(false);
}
/// <summary>
/// Get an array of string values from browser local storage.
/// </summary>
/// <param name="key">The key previously used to save to local storage.</param>
/// <returns>The array of string values previously saved to local storage.</returns>
public async Task<string[]> GetStringArrayAsync(string key)
{
var data = await jsruntime.InvokeAsync<string>("localStorage.getItem", key).ConfigureAwait(false);
if (!string.IsNullOrEmpty(data))
return data.Split('\0');
return null;
}
/// <summary>
/// Save an object value to browser local storage.
/// </summary>
/// <param name="key">The key to use to save to and retrieve from local storage.</param>
/// <param name="value">The object to save to local storage.</param>
public async Task SaveObjectAsync(string key, object value)
{
string str = string.Empty;
var bf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
using (var ms = new System.IO.MemoryStream())
{
bf.Serialize(ms, value);
var bytes = ms.ToArray();
foreach (var b in bytes)
str += b.ToString("X2");
}
await SaveStringAsync(key, str);
}
/// <summary>
/// Get an object from browser local storage.
/// </summary>
/// <param name="key">The key previously used to save to local storage.</param>
/// <returns>The object previously saved to local storage.</returns>
public async Task<object> GetObjectAsync(string key)
{
try
{
string str = await GetStringAsync(key);
if(str.Length % 2 == 0) // make sure string has an even number of character because one byte takes up two
{
var bytes = new byte[str.Length / 2];
for(int i = 0; i < bytes.Length; i++)
{
string val = str.Substring(i * 2, 2);
bytes[i] = byte.Parse(val, System.Globalization.NumberStyles.HexNumber);
}
using (var ms = new System.IO.MemoryStream(bytes))
{
var bf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
ms.Position = 0;
return bf.Deserialize(ms);
}
}
}
catch { }
return null;
}
}
}
The Progam.cs file must be modified as such (just one line of code is added).
// Program.cs
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Microsoft.Extensions.DependencyInjection;
namespace BlazorExample.Client
{
public class Program
{
public static async Task Main(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
// This AddSingleton line of code is for Uilities.LocalStorage to function - notice placement!
builder.Services.AddSingleton<Utilities.ILocalStorage, Utilities.LocalStorage>();
builder.RootComponents.Add<App>("app");
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
await builder.Build().RunAsync();
}
}
}