0

I need to read user id and some more data from session which is crucial to get specific data from the server, check permissions and rendering the screen.

I use Blazored.SessionStorage nuget to do that and use the following code line:

curData = await sessionStorage.GetItemAsync<CurrentData>("CurrentData");

At start I set the following line in OnInitializedAsync procedure but since session reading is async, the code proceeds and try loading data when there is no value in curData variable.

Then I tried to move session reading to SetParametersAsync which seems to be a better approach since this is the first procedure in the lifecycle. Same problem here.

So I tried some methods to wait for the await session to end but it did not work and it stuck the code and the code will not continue.

Bottom line I need help to find a way to load session data in SetParametersAsync and wait for it to finish reading before continue the component lifecycle.

Thanks all

Yaron Amar
  • 29
  • 6
  • What Identity provider do you use ? Why do you need to store the user id in the session storage? Are you acquianted with a similar library by Microsoft ? – enet Apr 18 '22 at 09:23
  • See this: https://learn.microsoft.com/en-us/aspnet/core/blazor/state-management?view=aspnetcore-6.0&pivots=server#aspnet-core-protected-browser-storage – enet Apr 18 '22 at 09:30
  • I use my own app identity – Yaron Amar Apr 18 '22 at 10:47
  • Why are you using client side sessionStorage? On any browser one can open up dev tools and modify the user id and permissions. – Yogi Apr 19 '22 at 09:39

1 Answers1

4

At start I set the following line in OnInitializedAsync procedure but since session reading is async, the code proceeds and try loading data when there is no value in curData variable.

That's not the issue... The issue is that in Blazor Server you can't perform any JS interop before your app is rendered.

Use the OnAfterRender{Async} lifecycle methods instead.

Note: The above answer is relevant only if your Blazor Server App has prerendering enabled. However, if prerendering is disabled, you should use OnParametersSetAsync, not OnInitializedAsync

UPDATE:

After previewing your code once again, I believe that the setting of CurentData had been successful, right? Without knowing wether pre-rendering in your app is enabled or not, you may do the following:

This code snippet may be used with pre-rendering disabled:

I believe this is the thing you're looking for...

@if (curData == null)
{
     @* Display here a spinner to indicate that data is being  
        loaded*@
     <p>Loading...</p>
}
else
{
   // put here your code that should be render when CurrentData 
   // is available 
}

@code {
    
  
    private CurrentData curData;

    protected override async Task OnInitializedAsync()
    {
         curData = await sessionStorage.GetItemAsync<CurrentData> 
                                               ("CurrentData");
    }

}

This code snippet may be used with pre-rendering enabled:

@if (isConnected)
{
    // put here your code that should be render when CurrentData 
    // is available
}
else
{
    <p>Loading...</p>
}

@code {
    
    private bool isConnected;
    private CurrentData curData;

    protected override async Task OnAfterRenderAsync(bool 
                                                   firstRender)
    {
        if (firstRender)
        {
            isConnected = true;
            await LoadStateAsync();
            StateHasChanged();
        }
    }

    private async Task LoadStateAsync()
    {
       curData = await sessionStorage.GetItemAsync<CurrentData> 
                                               ("CurrentData");
    }

}
enet
  • 41,195
  • 5
  • 76
  • 113
  • I will try that later on ... – Yaron Amar Apr 18 '22 at 10:46
  • 1
    Incidentally, what you do is wrong; I mean using the session storage. Session Storage is also not secure. Instead you should use in-memory state container service, which should be scoped to the circuit (connection), and injected into client components. חג שמח, חביבי – enet Apr 18 '22 at 11:08
  • Tx, any link to a code sample ? חג שמח גם לך – Yaron Amar Apr 19 '22 at 19:59
  • Link to a code sample ? That do what ? Create in-memory state container service ? This may help you how to create a service used by components: https://stackoverflow.com/a/62042629/6152891 And this is how you can pass values from the _Host.cshtml file to the Server Blazor App itself: https://stackoverflow.com/a/59538319/6152891, and then add the values to a state container service that you can inject into your components. You may also add services to the DI container with data retrieved at the same time. There are various ways to do things, – enet Apr 19 '22 at 21:31
  • and what mehtod you choose depend on various constraint, including your design and knowledge. I wouldn't like to add more content here, but if you have more questions, please email me: enet.studio1@gmail.com – enet Apr 19 '22 at 21:32
  • Now I understand what you meant, well I already tried that approach before but it will not work for my needs since Scoped Service clears once the user refresh the page or manually navigate to other page and Singleton will be overwritten when other user logged in. – Yaron Amar Apr 20 '22 at 05:59
  • @enet many thanks for this, the pre-rendered version. I spent hours trying to solve this. And your solution worked out of the box. – Brian.S May 10 '23 at 10:47