DEV Community

Nick Alonge
Nick Alonge

Posted on

Using Local Browser Storage in .NET MAUI Blazor Hybrid

This blog is part of the .NET MAUI UI July 2024 series with a new post every day of the month. See the full schedule for more.

This article explores how to leverage local browser storage in a .NET MAUI Blazor Hybrid application to enhance data management and user experience. By utilizing this powerful combination, developers can create robust and efficient apps that maintain state and persist data across sessions, providing users with a smooth and responsive interface.

I don't think I have written an application where I didn't need some kind of data persistence. Whether it be SQLite or a larger MS SQL database. A lot of apps only require storing small amounts of data, and using a RDBMS can be a lot of overhead and add unnecessary libraries that inflate the size of your app. Sometimes you have too much data for saving key/value pairs to Preferences, and not enough to warrant setting up a full blown database.

Since .NET 8, I have adopted MAUI Blazor Hybrid as my tool of choice for writing mobile applications. For the apps I write, having a consistent UI across iOS and Android is important, but also having access to the native platform is desirable as well. I have found the ease of storing data locally helps me speed up development of small to medium sized apps.

There are 3 types of browser storage:

Session Storage
Useful for storing data until that browser session is closed.

Local Storage
Local storage will persist even when the user quits the app and comes back.

Both Local and Session storage use key/value pairs and are limited to the amount of data (and type) you can store.

IndexedDB
For more complex data, without the storage limits of local and session storage, IndexedDB should be used. The IndexedDB API stores structured data, including files and blobs. You can also create indexes for high speed searches. Because IndexedDB is a little moved involved, I will create a dedicated post for it.

Examples

Let's get to the code. I will be using VS Code on the Mac with the .NET MAUI extension for this example. All the code will be available in Github.

We'll start with Local storage. Create a new MAUI-Blazor project. We will be using the sample pages the template creates. For local and session storage, we will be using the Blazored LocalStorage nugget. Add this to your project:

dotnet add package Blazored.LocalStorage

After the nugget installs, open up MauiProgram.cs and register the service:

using Blazored.LocalStorage;
using Microsoft.Extensions.Logging;

namespace MAUIHybridBrowserStorage;

public static class MauiProgram
{
    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();
        builder
            .UseMauiApp<App>()
            .ConfigureFonts(fonts =>
            {
                fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
            });

        builder.Services.AddMauiBlazorWebView();

                // Add the Blazored.LocalStorage service
        builder.Services.AddBlazoredLocalStorage();



#if DEBUG
        builder.Services.AddBlazorWebViewDeveloperTools();
        builder.Logging.AddDebug();
#endif

        return builder.Build();
    }
}

Enter fullscreen mode Exit fullscreen mode

That's it for setup. Now let's put it to use. Open up Home.razor. We are going to use this page to manage our shopping list.

Start by injecting the Blazored.LocalStorage service into our Home.razor page:

@inject Blazored.LocalStorage.ILocalStorageService localStorage

We will use the variable localStorage to access the injected service. Next, add the @code directive, and override OnInitializedAsync(). Our Home.razor file should now look like this:

@page "/"

@inject Blazored.LocalStorage.ILocalStorageService localStorage

<h3 class="text-center">Shopping List</h3>

@code 
{
    protected override async Task OnInitializedAsync()
    {

    }
}

Enter fullscreen mode Exit fullscreen mode

I removed the code and HTML generated by the template, and centered the page title using Bootstrap classes.

Now we will add a simple List to store our items, and read/write from that list to display the items on the page. In the OnInitializedAsync() method, we will check for any items saved to local storage, and if not NULL, set the ShoppingListItems to the value:

@code 
{
    List<string>? ShoppingListItems;

    protected override async Task OnInitializedAsync()
    {
        // Check local storage for any items
        ShoppingListItems = await localStorage.GetItemAsync<List<string>>("list-items");
    }
}
Enter fullscreen mode Exit fullscreen mode

Let's also add methods for adding and deleting the local storage items:

    private async Task AddItems()
    {
        string[] items = {"Lettuce", "Roasted Turkey Lunch Meat", "Nutty Buddy", "Iced Tea", "Frozen Pizza", "Dog Food"};

        ShoppingListItems = items.ToList();

        // Save to local storage
        await localStorage.SetItemAsync("list-items", items);
    }

    private async Task DeleteAllItems()
    {
        // Remove the key
        await localStorage.RemoveItemAsync("list-items");

        // Reset the Shopping List
        ShoppingListItems = await localStorage.GetItemAsync<List<string>>("list-items");
    }
Enter fullscreen mode Exit fullscreen mode

In Part 2 of this article, we will add and delete individual items, but for now we are just hard coding some values.

Here is the completed Home.razor file:

@page "/"

@inject Blazored.LocalStorage.ILocalStorageService localStorage

<h3 class="text-center">Shopping List</h3>

@if(ShoppingListItems != null)
{
    <div class="container">
        <table class="table table-striped">
            <thead>
                <tr>
                    <th>Item</th>
                </tr>
            </thead>
            <tbody>
                @foreach(var item in ShoppingListItems)
                {
                    <tr>
                        <td>@item</td>
                    </tr>
                }
            </tbody>
        </table>
        <br />
        <div class="text-center">
            <button class="btn btn-danger" @onclick="DeleteAllItems">Delete List</button>
        </div>
    </div>
} else 
{
    <p class="text-center mt-3">No items in the list.  Click the Add Items button</p>
    <div class="text-center">
        <button @onclick="AddItems" class="btn btn-primary">Add Items</button>
    </div>
}

@code 
{
    List<string>? ShoppingListItems;
    protected override async Task OnInitializedAsync()
    {
        // Check local storage for any items
        ShoppingListItems = await localStorage.GetItemAsync<List<string>>("list-items");
    }

    private async Task AddItems()
    {
        string[] items = {"Lettuce", "Roasted Turkey Lunch Meat", "Nutty Buddy", "Iced Tea", "Frozen Pizza", "Dog Fooo"};

        ShoppingListItems = items.ToList();

        // Save to local storage
        await localStorage.SetItemAsync("list-items", items);
    }

    private async Task DeleteAllItems()
    {
        // Remove the key
        await localStorage.RemoveItemAsync("list-items");

        // Reset the Shopping List
        ShoppingListItems = await localStorage.GetItemAsync<List<string>>("list-items");
    }
}

Enter fullscreen mode Exit fullscreen mode

When you run the app add the items, they will persist until you delete them (or the app is removed). In Part 2 we will take a look at how to use the web browser development tools in Chrome, Edge or Safari to view our local storage data.

Using Local Storage is an easy way to persist data in your application without needed any knowledge of a relational database system. And .NET MAUI Blazor Hybrid gives you all the conveniences of a web application in a native app.

In Part 2 we will focus on IndexedDB to store complex data types. We will also use JS Interop to access some simple Javascript for user interaction.

Thanks for reading, I hope you enjoyed this article and stay tuned for more.

Top comments (0)