Havit.Blazor.Storage provides strongly-typed access to the browser Web Storage areas
– window.localStorage and window.sessionStorage – from your Blazor application.
It exposes two services, ILocalStorageService and ISessionStorageService, both implementing the same
IBrowserStorage interface. You can store and retrieve plain string values or any object (serialized to/from JSON).
Add the Havit.Blazor.Storage NuGet package to your Blazor project.
In a Blazor Web App with a separate .Client project, add it to the project where you intend to consume the storage
(typically the .Client project, so that the synchronous API is available in the WebAssembly render mode).
dotnet add package Havit.Blazor.StorageRegister the services in your Program.cs:
using Havit.Blazor.Storage;
builder.Services.AddHavitBlazorStorage();
This registers both ILocalStorageService and ISessionStorageService with a Scoped lifetime.
No <script> reference is required – the small supporting JavaScript module is loaded automatically by the Blazor JS initializer.
Inject ILocalStorageService and/or ISessionStorageService into your component. Both share the same API
(IBrowserStorage), so the only difference is which browser storage area they target.
@inject ILocalStorageService LocalStorage
<button @onclick="StoreAsync">Store</button>
<button @onclick="LoadAsync">Load</button>
<p>@_value</p>
@code {
private string _value;
private async Task StoreAsync()
{
await LocalStorage.SetStringValueAsync("greeting", "Hello world!");
}
private async Task LoadAsync()
{
var (success, value) = await LocalStorage.TryGetStringValueAsync("greeting");
_value = success ? value : "<not stored yet>";
}
}
Every operation comes in two flavors – a synchronous one (e.g. GetStringValue) and an asynchronous one (e.g. GetStringValueAsync).
IJSRuntime and work in any render mode
(Interactive Server, Interactive WebAssembly, Auto).
IJSInProcessRuntime, which is only available in the
Interactive WebAssembly render mode. Calling them in any other context throws an
InvalidOperationException.
localStorage/sessionStorage
objects do not exist on the server. Access the storage only once the component has become interactive
(for example from an event handler, or from OnAfterRender(Async) once the component is interactive), not during prerendering.
The synchronous API is convenient in a WebAssembly app, where it avoids the asynchronous state machine:
@inject ILocalStorageService LocalStorage
@code {
protected override void OnAfterRender(bool firstRender)
{
// OnAfterRender runs only on the (WebAssembly) client once the component is interactive,
// which guarantees the IJSInProcessRuntime required by the synchronous methods is available.
if (firstRender)
{
if (LocalStorage.TryGetStringValue("greeting", out var value))
{
// ...
}
}
}
}
Beside the raw string methods (SetStringValue/GetStringValue), you can store any value with
SetValue<TValue> and read it back with GetValue<TValue>. The value is serialized to/from JSON
using System.Text.Json.
public record UserPreferences(string Theme, bool CompactMode);
// store
await LocalStorage.SetValueAsync("preferences", new UserPreferences("dark", CompactMode: true));
// read
var (success, preferences) = await LocalStorage.TryGetValueAsync<UserPreferences>("preferences");
// read (throws StorageKeyNotFoundException when the key is missing)
var preferences2 = await LocalStorage.GetValueAsync<UserPreferences>("preferences");
You can configure the default JsonSerializerOptions used by SetValue/GetValue (and their async variants)
during the service registration. The options are used whenever no JsonSerializerOptions are passed to the individual method call.
builder.Services.AddHavitBlazorStorage(new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
});
// or via the options delegate:
builder.Services.AddHavitBlazorStorage(options =>
{
options.JsonSerializerOptions = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};
});Individual calls can always override the configured options by passing their own JsonSerializerOptions.
All members are available in both synchronous and asynchronous (suffixed with Async) variants on IBrowserStorage:
SetStringValue / GetStringValue – store and read a raw string value.TryGetStringValue – read a string value without throwing when the key is missing.SetValue<T> / GetValue<T> – store and read a JSON-serialized object.TryGetValue<T> – read a JSON-serialized object without throwing when the key is missing.Remove – remove a single key.Clear – remove all keys from the storage area.GetLength – the number of keys stored.GetKeyByIndex / TryGetKeyByIndex – enumerate the keys by their zero-based index.Get* / GetKeyByIndex methods throw StorageKeyNotFoundException /
StorageIndexOutOfRangeException when the requested key/index is not present.
Use the TryGet* overloads when a missing value is an expected, non-exceptional case.
The storage methods can throw the following exceptions:
StorageNotAvailableException – the storage area is not accessible (e.g. disabled or blocked by the browser privacy settings).StorageKeyNotFoundException – thrown by GetStringValue/GetValue when the key is not present.StorageIndexOutOfRangeException – thrown by GetKeyByIndex when the index is out of range.InvalidOperationException – thrown by the synchronous methods when IJSInProcessRuntime is not available (i.e. not in the Interactive WebAssembly render mode).ArgumentException / ArgumentNullException – thrown when invalid arguments are provided (e.g. key is null/whitespace, or a stored value is null).try
{
var token = await LocalStorage.GetStringValueAsync("token");
// ...
}
catch (StorageKeyNotFoundException)
{
// the key has not been stored yet
}
catch (StorageNotAvailableException)
{
// storage is disabled/blocked in the browser
}