Home > front end >  Blazor webassembly, Setting service in App's OnInitializedAsync, can't get in Counter.razo
Blazor webassembly, Setting service in App's OnInitializedAsync, can't get in Counter.razo

Time:06-27

In blazor webassembly, I have a singleton service containing this property:

public IsAuthenticatedModel Auth { get; set; } = null;

I set this property in Login page:

 await genericService.SetSession<IsAuthenticatedModel>("AuthModel", ViewData.AuthModel);
 mzSingleton.Auth = ViewData.AuthModel;

First I save the data in the server session then I store it in the singleton service that I can access in the app.

In the following code in App.razor, I check if the Singleton property is null then fill it with the data comming from server's session:

protected override async Task OnInitializedAsync()
        {
            if (mzSingleton.Auth == null)
                mzSingleton.Auth = await genericService.GetSession<IsAuthenticatedModel>("AuthModel")
                    ?? new IsAuthenticatedModel();

        }

I do all of this because I want to keep service's data after refreshing the page.

Unfortunately this code does not work immediately after refresh. when I access the singleton service in the counter page, I have to go to another page and comeback to for it to work (Once I read, in new versions of blazor component rendering is from child to parent).

Is there a workaound for this problem other than cascading parameters? I use .Net 6.

EDIT:

in the Login page i set the service property:

await genericService.SetSession<IsAuthenticatedModel>("AuthModel", AuthModel);                
mzSingleton.Auth = AuthModel;

in the Counter.razor page:

@if (mzSingleton.Auth != null)
{
    <h1>2 (serverside session)</h1>
    <label>Is Authenticated: </label><label>@mzSingleton.Auth.IsAuthenticated</label>
    <label>User: </label><label>@mzSingleton.Auth.User</label>
    @if (mzSingleton.Auth.Roles?.Count > 0)
    {
        foreach (string role in mzSingleton.Auth.Roles)
        {
            <label>Role: </label><label>@role</label>
        }
    }
}

As I said after refreshing counter page the mzSingleton.Auth has no value, But after doing something (when statehaschanged is fired) the page shows Auth values correctly!

EDIT2:

Since I get two objects from server's session I reveresed session calls order and this time my Auth service worked and my other service NOT:

protected override async Task OnInitializedAsync()
{
    await base.OnInitializedAsync();
            
    mzSingleton.Auth = await genericService.GetSession<IsAuthenticatedModel>("AuthModel");

    mzSingleton.MyBooz = await genericService.GetSession<Booz>("Booz");

    StateHasChanged();    
}

So I suspected to 'async' so I replaced OnInitializedAsync to OnInitialized the synchronous version. So I had to remove await and add result like this:

genericService.GetSession<IsAuthenticatedModel>("AuthModel").Result; 

But I get a Blazor error that says: "Cannot wait on monitors on this runtime.", So I forced to change the genericservice methods to synchronous versions:

public async Task<T> GetSession<T>(string key) where T : class, new()
to 
public T GetSession<T>(string key) where T : class, new()

But inside this method I use:

await httpClient.GetJsonAsync<SessionKeyValue>($"api/Session/GetSession/{key}");

If I remove await and Use .Result at the end I get the same error. and if I want to use non async .GetJson() There is no such method in Blazor's HttpClient. So I locked to use Async methods. And if there are two Async calls in OnInitializedAsync one of them executes with delay, And is not ready after page refresh!

CodePudding user response:

I solved my problem with this trick: first I defined ServicesSet property in the singleton service:

public class MzSingleton
    {
        public Booz MyBooz { get; set; }

        public IsAuthenticatedModel Auth { get; set; }
        
        public Action ServicesSet { get; set; }
    }

Then in the App.razor:

protected override async Task OnInitializedAsync()
        {
            await base.OnInitializedAsync();
           
            mzSingleton.Auth = await genericService.GetSession<IsAuthenticatedModel>("AuthModel");
            mzSingleton.MyBooz = await genericService.GetSession<Booz>("Booz");
            mzSingleton.ServicesSet?.Invoke();            
            
        }

And in Counter.razor:

protected override async Task OnInitializedAsync()
    {
        await base.OnInitializedAsync();

        mzSingleton.ServicesSet  = () => StateHasChanged();
    }
  • Related