0

I am trying to impliment a darkmode toggle in a blazor webassembly app. I inject the localstorage and it works on other pages that use local storage but when trying to impliment it on the main layout oninitalized method I get a null reference error on load.

public partial class MainLayout
{
[Inject]
    protected ILocalStorageService localStorage { get; set; }
protected override async Task OnInitializedAsync()
    {
        _darkmode = false;
        try
        {

            if (await localStorage.GetItemAsStringAsync("theme") == null) return;
            var mode = await localStorage.GetItemAsync<string>("theme");
            if (!string.IsNullOrEmpty(mode))
                _darkmode = mode == "darkmode" ? true : false;

            Themer.SetTheme(_darkmode);
            StateHasChanged();
        }
        catch (Exception ex)
        {
            _darkmode = false;

        }         

    }
}

This is the error I get as soon as I have anything to do with the local storage in the main layout.

crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100] Unhandled exception rendering component: Object reference not set to an instance of an object. System.NullReferenceException: Object reference not set to an instance of an object. at SeekaPortal.Client.Shared.MainLayout.BuildRenderTree(RenderTreeBuilder __builder) at Microsoft.AspNetCore.Components.ComponentBase.<.ctor>b__6_0(RenderTreeBuilder builder) at Microsoft.AspNetCore.Components.Rendering.ComponentState.RenderIntoBatch(RenderBatchBuilder batchBuilder, RenderFragment renderFragment) at Microsoft.AspNetCore.Components.RenderTree.Renderer.RenderInExistingBatch(RenderQueueEntry renderQueueEntry) at Microsoft.AspNetCore.Components.RenderTree.Renderer.ProcessRenderQueue()

  • Please post the full error message. – Jesse Good Feb 17 '22 at 22:02
  • Sorry @JesseGood I have updated the OP – Martin Dempsey Feb 17 '22 at 22:21
  • you sure its localstrage thats null? We cant tell from the error message, but I would expect to see an OnInitializedAsync stack frame at the top. PLus this code catches the error – pm100 Feb 17 '22 at 22:26
  • @pm100 it has to be, not sure why the catch isn't working but if i comment out the localstorage line it runs, as soon as I put it in there I get an error in chrome – Martin Dempsey Feb 17 '22 at 22:30
  • sounds more like a timing issue, blazor willl go off and render things while you code is in off doing await things. I will post an answer with what I had to do – pm100 Feb 17 '22 at 22:34
  • @MartinDempsey: The error you posted has nothing to do with local storage. Most likely there is something in the markup that you don't show. – Jesse Good Feb 17 '22 at 23:33

1 Answers1

0

Blazor has some odd startup sequenceing behavior due to it rendering while pages are still running their startup logic (good old async, await...). Not sure if this is your issue or not. This is what I had to do

@if (BootComplete) {
    <Router AppAssembly="@typeof(App).Assembly">
        <Found Context="routeData">
            <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
            <FocusOnNavigate RouteData="@routeData" Selector="h1" />
        </Found>
        <NotFound>
            <PageTitle>Not found</PageTitle>
            <LayoutView Layout="@typeof(MainLayout)">
                <p role="alert">Sorry, there's nothing at this address.</p>
            </LayoutView>
        </NotFound>
    </Router>
}
@inject IJSRuntime JS
@inject SavedData Saver


@code 
{

    // boot code. By hiding everything nothing starts until bootcomplete is set to true
    // that is done after the successful exit from OnInitializedAsync
    // App.Boot has to be async becuase it does 'IO'

    bool BootComplete = false;

    protected override async Task OnInitializedAsync() {
        EarWorm.Code.Util.Init(JS);
        await Saver.Boot();
        BootComplete = true;
    }
 }

ie hide the UI until all injects, inits, reading of state etc had completed. I did it for the entire app (as you can see this is App.razor) maybe you need it for a few pages.

pm100
  • 48,078
  • 23
  • 82
  • 145
  • Thanks, seems like it was a timing issue. I moved all the theme loading/logic to it's own service and inherited it in the mainlayout and now seems to be working as intended – Martin Dempsey Feb 17 '22 at 23:51