One way to have data persist across sessions in a client-side Blazor WebAssembly application is to write to the browser’s LocalStorage or SessionStorage collection. This will allow the user to refresh or re-open the page and have the same experience as when they last left off.
In previous tutorials, you already learned how to pass application data between different pages and components during a single session, but there are situations when you may want data to persist across sessions in your client-side application. In a server-side application, you could simply save the data into a SQL database or other store. In a WebAssembly application, however, can use the browser’s LocalStorage
or SessionStorage
collection as a backing store.
Protecting Data Storage
Though this tutorial will not be storing sensitive data, it is good practice to encrypt stored data. ASP.NET Core provides a simple data protection stack that can be used for such purposes. In the future, it may be recommended to use a package such as Microsoft’s ProtectedBrowserStorage Nuget package, which provides data protection.
As of this writing, that package is still in early development, and it cannot target netstandard, a requirement of Mono WebAssembly. Therefore, I will be using the Blazored.LocalStorage package. Simply install it via the Package Manager Console.
Install-Package Blazored.LocalStorage
Blazor.LocalStorage Setup
To use the Blazored.LocalStorage
package, you must register its service with your application’s service collection in your project’s Startup.cs file. Start by adding a using statement for the Blazored.LocalStorage
namespace to the top of Startup.cs.
using Blazored.LocalStorage;
Then, register the service in the ConfigureServices()
method of Startup.cs.
public void ConfigureServices(IServiceCollection services)
{
services.AddBlazoredLocalStorage();
}
Now that the service is configured, go ahead and import the package’s namespace in the project’s _Imports.razor file. This will allow you to use the package in all your .razor components without having to explicitly add a using
directive for each component.
@using Blazored.LocalStorage;
You are now ready to begin writing data to the browser’s LocalStorage collection. Open Pages/Index.razor and paste the following content.
@page "/"
<h1>Your LocalStorage Note</h1>
<textarea @bind="noteContent" />
<br />
<button @onclick="UpdateLocalStorage">Save</button>
<button @onclick="ClearLocalStorage">Clear</button>
This will display a textarea
field that will contain the content of the note. There is also a Save button, which will be used to write to the browser’s local store, and a Clear button which will clear all locally stored data.
Blazor Save to LocalStorage
To begin using Blazored.LocalStorage
, inject an instance of the desired service into your page. At the top of Index.razor , add the following line:
@inject Blazored.LocalStorage.ILocalStorageService localStore
Now, declare a string
variable to hold the contents of the textarea
element, and create the event handlers that will correspond to each button’s onclick
event. The shell may look like the following:
@code{
string noteContent;
public async void UpdateLocalStorage()
{
}
public async void ClearLocalStorage()
{
}
}
To write an item to LocalStorage asynchronously using Blazored.LocalStorage
, you will use a key-value structure.
await localStore.SetItemAsync(key, value);
where localStore
corresponds to the name you assigned when injecting the instance, and key
and value
are both strings.
const string noteKey = "note";
string noteContent;
public async void UpdateLocalStorage()
{
await localStore.SetItemAsync(noteKey, noteContent);
}
Blazor Clear LocalStorage
Blazored.LocalStorage
also includes convenient methods for clearing individual items by key
await localStore.RemoveItemAsync(key);
and for clearing all stored items.
await localStore.ClearAsync();
Your ClearLocalStorage
handler may look like the following:
public async void ClearLocalStorage()
{
noteContent = "";
await localStore.ClearAsync();
}
Blazor Read LocalStorage
In order for the application to populate the textarea
with the value stored in LocalStorage
, you must override the page’s OnInitialized()
method. Specifically, to read the value asynchronously, override the async
method OnInitializedAsync()
.
protected override async Task OnInitializedAsync()
{
}
In this method, you should assign the stored value to the binding variable you are using for the textarea
element, in this case noteContent
.
To fetch the value of an item from LocalStorage, you will use the item’s key
as its identifier.
protected override async Task OnInitializedAsync()
{
noteContent = await localStore.GetItemAsync<string>(noteKey);
}
The Final Product
Your completed index.razor page will look similar to the following:
@inject Blazored.LocalStorage.ILocalStorageService localStore
@page "/"
<h1>Your LocalStorage Note</h1>
<textarea @bind="noteContent" />
<br />
<button @onclick="UpdateLocalStorage">Save</button>
<button @onclick="ClearLocalStorage">Clear</button>
@code{
const string noteKey = "note";
string noteContent;
public async void UpdateLocalStorage()
{
await localStore.SetItemAsync(noteKey, noteContent);
}
public async void ClearLocalStorage()
{
noteContent = "";
await localStore.ClearAsync();
}
protected override async Task OnInitializedAsync()
{
noteContent = await localStore.GetItemAsync<string>(noteKey);
}
}

At the beginning, when you install the package, I think you meant to install the other one. You have:
Install-Package Microsoft.AspNetCore.ProtectedBrowserStorage -Version 0.1.0-alpha.19521.1
Shouldn’t it be “Blazored.LocalStorage”?
Good find! Thanks for catching this. I made the correction
Thanks Bradley, nicely done. If you have a minute, I’d appreciate your thoughts on my problem.
My application loads data for 6 dropdowns from an API, but it is a significant amount of data that changes rarely on the backend system.
The data from the API is deserialised into an object that contains all of the data for the 6 dropdowns.
I’d like for the application to store it (presumably as described in your article above), but I need to build in a mechanism that updates from the backend if the data is stale or has changed on the backend.
Any ideas, I guess this may be a common scenario in SPA’s?
Regards,
Steve Bond
Hi Bradley,
Can you please use Newtonsoft.Json instead of System.Text.Json, because it does not work in azure functions (exception : Could not load file or assembly System.Text.Json), it does work well when executed on a “normal” computer
Thanks
Rafik
thanks, it woks good in pwa
thank you Bradley Wells
minor little typo, C# case sensitive:
@inject Blazored.LocalStorage.ILocalStorageService LocalStore
everywhere else it is referenced as lower case localStore
Thanks for pointing this out. Fixed!
Can LocalStorage save Objects (POCO) or only strings as in this example?
I created a WASM that injects a List of Objects into a razor page that takes a good 15 seconds
to load. I was hoping to only pay that time price once by saving the Objects into LocalStorage
such that the list would remain when I return to that page. Is that possible?
It can save objects. It will automatically serialize them.
Hello,
I struggle to save objects to the session storage. Is this possible?
Example:
TestObject testObject = new TestObject();
protected override async Task OnInitializedAsync()
{
test = await sessionStorage.GetItemAsync(“test”);
}
async Task FunctionWhichIsCalledOnButtonPress()
{
await sessionStorage.SetItemAsync(“test”, testObject);
}
How can I create a new instance of the object in the session storage or is it created automatically? If I use a string, everything works flawless. But I can´t get Blazored to store a custom object of mine.
Thanks in advance!
In a WASM Blazor App, how can I inject the Blazored LocalStorage into a service?
I currently have a service on my client that I am using to get/set app settings but when I try to inject into the service I get an error saying you cannot inject a Scoped into my Singleton?
Thoughts?
Thanks for the information. Is there a way in write/read localstorage via a service in a WASM client? Currently I cannot get an instance LocalStorage in service because you cannot Inject in a service.
Any thoughts would be helpful as I would like to access the storage via a shared service, not a component.
Thanks
I really love your post. Thanks for sharing it with us.
I appreciated your post. however I am getting a service error. Perhaps you can shed some light.
I Installed Blazored.LocalStorage by Chris Sainty V3.0.0
I added the using in Startup
I added services.AddBlazoredLocalStorage(); in ConfigureServices in Startup
I added the Imports using statement, @using Blazored.LocalStorage;
Then I added the inject on my page: @inject Blazored.LocalStorage.ILocalStorageService lss
Everything Build correctly. But without even referencing the ‘lss’ object I get the following error:
There is no registered service of type ‘Blazored.LocalStorage.ILocalStorageService’.
Any ideas? Thanks
Hi Bradley thank you very much for sharing your knowledge :).
maybe Iam doing it wrong, but it seems that MS has changes some stuff inBlazor maybe with net.5?
protected override async Task OnInitializedAsync() { … }
Is not working in this example anymore as it shut. You have to modefy alitte for that.
The setup stuff stayes the same.
For readers after my post take this to play with (till MS changes again) (right now working with NET.5.0 Blazor Serverside):
@page “/”
@inject Blazored.LocalStorage.ILocalStorageService localStorage
Local Storage Test
Storages:
@Name
@*—————————-*@
Save
Clear
Load
@code{
string Name = “”;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
await localStorage.SetItemAsync(“name”, “John Smith”);
var name = await localStorage.GetItemAsync(“name”);
Name = name;
StateHasChanged();
}
//————————–https://wellsb.com/csharp/aspnet/blazor-write-to-localstorage/
const string noteKey = “note”;
string noteContent;
public async void UpdateLocalStorage()
{
await localStorage.SetItemAsync(noteKey, noteContent);
}
public async void ClearLocalStorage()
{
noteContent = “”;
await localStorage.ClearAsync();
}
public async void LoadLocalStorage()
{
noteContent = await localStorage.GetItemAsync(noteKey);
}
}
Dang the ForumApp cleared the Markup stuff of my code 🙁
Reades beware and fill the stuff that is missing e.g.
button onclick save etc.
You work it out (sorry for that, wanted to make it super simple to use -> didnt work and now it is as usual you have to put some effort into it to use stuff before copy paste)
Tltr:
NOTE: Due to pre-rendering in Blazor Server you can’t perform any JS interop until the OnAfterRender lifecycle method.
Same problem here. I’m using Blazor 5.0 and by design it’s not possible to use this sample code in OnInitializedAsync() anymore. Instead, we should use OnAfterRenderAsync(bool firstRender) if we want to use JSInterop.
Thank you for sharing this blog with us its very useful for everyone.