Local storage in Blazor Server

Local storage is an internal database created into the browser, which you can use to save data in a key-value format. The data stored in local storage has no expiration date and will persist until the user decides to delete it.

This guide describes how to manage the data from local storage.

You can download the example code used in this topic on GitHub.

Manage local storage with ProtectedLocalStorage

ProtectedLocalStorage is a built-in class that allows programmers to manage local storage. The data stored by ProtectedLocalStorage is encrypted but at the cost of incrementing the size of the data. Local storage has a limit of 5MB per site unless the user wants more.

ProtectedLocalStorage only available on the client side. If you use ProtectedLocalStorage on any server life cycle methods like OnInitialized() you will get an error. Look at Lifecycle event sequence table to see what lifecycle methods are triggered by the client side.

Using ProtectedLocalStorage in a component

To use ProtectedLocalStorage in a component, you need to inject it in the directive section of the component.

@using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage
@inject ProtectedLocalStorage ProtectedLocalStorage

Using ProtectedLocalStorage in a service

To use ProtectedLocalStorage in a service, you need to inject it in the constructor of the service.

public class <Class Name>
{
    private readonly ProtectedLocalStorage _protectedLocalStorage;

    public <Class Name>(ProtectedLocalStorage protectedLocalStorage)
    {
        _protectedLocalStorage = protectedLocalStorage;
    }
}

Storing and retrieving local storage without scope

To store data in local storage, you need to call the method SetAsync(key, value) of ProtectedLocalStorage. In our example, we have set up a form to store data to the local storage.

<form>
    <div>
        <label>Key: <input type="text" @bind-value="LocalStorageKey" /></label>
    </div>
    <div>
        <label>Value: <input type="text" @bind-value="LocalStorageValue" /></label>
    </div>
    <div>
        <button type="button" @onclick="StoreKeyAsync">Store Key</button>
    </div>
</form>

@code {
    public string LocalStorageKey { get; set; }
    public string LocalStorageValue { get; set; }

    private async Task StoreKeyAsync()
    {
        await ProtectedLocalStorage.SetAsync(LocalStorageKey, LocalStorageValue);
    }
}

To retrieve data from local storage, you need to call the method GetAsync(key) of ProtectedLocalStorage. In our example, we have set up a form to get the data from local storage.

<form>
    <div>
        <label>Key: <input type="text" @bind-value="LocalStorageQueryKey" /></label>
    </div>
    <div>
        <button type="button" @onclick="GetValueAsync">Get Value</button>
    </div>
    <div>Value: @LocalStorageQueryValue</div>
</form>

@code {
    public string LocalStorageQueryKey { get; set; }
    public string LocalStorageQueryValue { get; set; }

    private async Task GetValueAsync()
    {
        var result = await ProtectedLocalStorage.GetAsync<string>(LocalStorageQueryKey);
        
        if (result.Success)
        {
            LocalStorageQueryValue = result.Value;
        }
    }
}

If you use the ProtectedLocalStorage to store the data then you can only use ProtectedLocalStorage to retrieve the value back because the actual data stored in the browser will be encrypted.

Scoped local storage

Just like CSS, the data in local storage can be scoped. Although you cannot have a key multiple times, you can divide them into areas so the key in one area cannot access the others. Keep in mind that local storage keys are case-sensitive.
To store the data in scope, you need to call SetAsync(purpose, key, value) of ProtectedLocalStorage. The purpose parameter is important as it will be used to retrieve the key later on. You can reuse the previous example and change the SetAsync method as:
...
private async Task StoreKeyAsync() 
{ 
    await ProtectedLocalStorage.SetAsync("login", LocalStorageKey, LocalStorageValue);
}

To retrieve the data in scope, you need to call the method GetAsync(purpose, key) of ProtectedLocalStorage.

...
private async Task GetValueAsync()
{
    ProtectedBrowserStorageResult<string> result = new();

    try
    {
        result = await ProtectedLocalStorage.GetAsync<string>("login", LocalStorageQueryKey);
    }
    catch
    {
    }
    finally
    {
        LocalStorageQueryValue = result.Success ? result.Value : "Not success.";
    }
}

Anytime you are accessing the scoped local storage, you should wrap it in a try catch block because if you don't, Blazor Server will emit an error Error: System.Security.Cryptography.CryptographicException: The payload was invalid and stop the website.

Deleting data from local storage

To delete a key from local storage, call the method DeleteAsync(key) of ProtectedLocalStorage. Deleting a key does not distinguish if the data is scoped data or not.

Manage local storage with JavaScript

Although you can use ProtectedLocalStorage to access local storage, you can also use JavaScript to access the local storage. There are several advantages when using JavaScript to deal with local storage, some of them are:

  • See the list of local storage keys.
  • Lightweight data.
  • Clear all data.

JavaScript is only available on the client side. If you use JavaScript on any server life cycle methods like OnInitialized() you will get an error. Look at Lifecycle event sequence table to see what lifecycle methods are triggered by the client side. The following are the steps for using JavaScript to manage local storage, it does not cover how to interact with JavaScript in Blazor Server. For understand how to interact with JavaScript, look at JavaScript Interaction.

  1. Create a new BlazorUtil.js file under folder wwwroot/js.
class BlazorUtil
{
    getAllStorage()
    {
        return Object.entries(localStorage);
    };
}

window.BlazorUtil = new BlazorUtil();
  1. Import the BlazorUtil.js file in _Host.cshtml.
  2. Inject IJSRunTime into the component or the service.
  3. Call JavaScript to manage local storage.

Storing data into local storage

To store the data in local storage, call the setItem(keyName, keyValue) of the localStorage. In our example, we have set up a form to store data to the local storage.

<form>
    <div>
        <label>Key: <input type="text" @bind-value="LocalStorageKey" /></label>
    </div>
    <div>
        <label>Value: <input type="text" @bind-value="LocalStorageValue" /></label>
    </div>
    <div>
        <button type="button" @onclick="StoreKeyAsync">Store Key</button>
    </div>
</form>

@code {
    public string LocalStorageKey { get; set; }
    public string LocalStorageValue { get; set; }

    private async Task StoreKeyAsync()
    {
        await JSRuntime.InvokeVoidAsync("localStorage.setItem", LocalStorageKey, LocalStorageValue);
    }
}

Retriving and deleting data into local storage

To retrieve the data in local storage, call the getItem(keyName) of the localStorage. In our example, we have set up a form to retrieve data from the local storage.

<form>
    <div>
        <label>Key: <input type="text" @bind-value="LocalStorageQueryKey" /></label>
    </div>
    <div>
        <button type="button" @onclick="GetValueAsync">Get Value</button>
        <button type="button" @onclick="DeleteValueAsync">Delete Key</button>
    </div>
    <div>Value: @LocalStorageQueryValue</div>
</form>

@code {
    public string LocalStorageQueryKey { get; set; }
    public string LocalStorageQueryValue { get; set; }

    private async Task GetValueAsync()
    {
        LocalStorageQueryValue = await JSRuntime.InvokeAsync<string>("localStorage.getItem", LocalStorageQueryKey);
    }

    private async Task DeleteValueAsync()
    {
        await JSRuntime.InvokeAsync<string>("localStorage.removeItem", LocalStorageQueryKey);
    }
}

Retriving and cleaning all the data in local storage

To retrieve all the data in the local storage is a bit different because in .NET 5, Blazor Server is not supporting for referring JavaScript objects, you have to use the method we have created BlazorUtil.js. In our example, we have created a form to demonstrate the feature.

<div>
    <div>All local storage data:</div>
    <button type="button" @onclick="GetAllLocalStorageDataAsync">Refresh</button>
    <button type="button" @onclick="ClearAllDataAsync">Clean All</button>
    @foreach (KeyValuePair<string, string> keyValuePair in AllData)
    {
        <div>@keyValuePair.Key: @keyValuePair.Value</div>
    }
</div>

@code {
    public Dictionary<string, string> AllData { get; set; } = new();

    private async Task GetAllLocalStorageDataAsync()
    {
        var jsonElement = await JSRuntime.InvokeAsync<JsonElement>("BlazorUtil.getAllStorage");
        var enumerator = jsonElement.EnumerateArray();
        AllData.Clear();

        while (enumerator.MoveNext())
        {
            var keyValue = JsonConvert.DeserializeObject<List<string>>(enumerator.Current.GetRawText());
            AllData.Add(keyValue[0], keyValue[1]);
        }
    }

    private async Task ClearAllDataAsync()
    {
        await JSRuntime.InvokeVoidAsync("localStorage.clear");
    }
}
BLAZOR SCHOOL
Designed and built with care by our dedicated team, with contributions from a supportive community. We strive to provide the best learning experience for our users.
Docs licensed CC-BY-SA-4.0
Copyright © 2021-2025 Blazor School
An unhandled error has occurred. Reload 🗙