Reputation: 13
In a Blazor Static SSR project, how do interactive components receive a parameter?
I created a simple project on github to demonstrate the problem.
This is a Blazor Static SSR project, with interactive components. In program.cs, it uses:
builder.Services.AddRazorComponents().AddInteractiveServerComponents();
The requirements are: The pages are non-interactive (EditForms with submit). The project cannot have globally available interactivity (such as Blazor Server).
On many pages, we want to include an interactive component.
When a noninteractive page includes an interactive component, Blazor will not let you use the standard method of including a parameter such as: ChildInteractive userid="aaa" ChildInteractive.
The solution seems to be set the parameter in program.cs This is done using: builder.Services.AddCascadingValue("UserID", sp => (string)"Initial value, set in Program.cs");
That Cascading Parameter is available to all components.
(BTW, in a Static SSR project, Cascading Parameters set in Routes.razor are only available to non-interactive components.)
My question is: The cascading parameter is set using builder.Services.AddCascadingValue. But, how do you modify the value? In my case, the parameter is the logon UserID. However, the UserID is not known until the user logs in. Therefore, once the user logs in, the cascading parameter, UserID, needs to be updated.
Sample project:
https://github.com/ssperoniGIT/Blazor-SSR-Params
It seems the only solution is to set the parameter before the projects starts, by setting it in program.cs. But it needs to be updated.
Upvotes: 1
Views: 622
Reputation: 8616
You could use try Browser Localstorage to save personal data for each User. And remove the storage when log out. But as SSR c# code only run on server and cannot access browser localstorage, you have to use javascript. Use javascript to access localstorage is also very simple. You could try following sample:
1.install Blazored.LocalStorage
package.
Program.cs
builder.Services.AddBlazoredLocalStorage();
2.Modify ChildInteractive
like below: (I used the counter number as UserID, Use "click me" to update this ID to storage, and use "logout" to reset the id and clear the storage )
@rendermode @(new InteractiveServerRenderMode(prerender: false))
@inject Blazored.LocalStorage.ILocalStorageService localStorage
@inject NavigationManager manager
<p role="status">Child Current Id: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
<button class="btn btn-primary" @onclick="Clear">LogOut Clear</button>
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
localStorage.SetItemAsStringAsync("UserId",currentCount.ToString());
manager.NavigateTo("/");
}
protected override async Task OnInitializedAsync()
{
var a = await localStorage.GetItemAsStringAsync("UserId");
currentCount = (a != null) ? Int32.Parse(a) : 0;
}
private async Task Clear()
{
currentCount = 0;
await localStorage.RemoveItemAsync("UserId");
manager.NavigateTo("/");
}
}
3.Modify Home.razor like below: (We use BlaozrPageScript
here, it allows you to execute js code when navigate without forcereloading https://learn.microsoft.com/en-us/aspnet/core/blazor/javascript-interoperability/static-server-rendering?view=aspnetcore-8.0)
@page "/"
@using BlazorPageScript
<PageScript Src="./Components/Pages/Home.razor.js" />
<p >Parent UserId = <label id="UserId">0</label></p>
<ChildInteractive></ChildInteractive>
4.Create a Home.razor.js like below:
export function onUpdate() {
var id = localStorage.getItem("UserId");
document.getElementById("UserId").innerHTML = id?id:0;
}
Then you will find SSR parent and InterActive Child are using same value from localstorage and can be update at the same time.
By the way, the official template get identity using PersistingRevalidatingAuthenticationStateProvider
which uses UserManager that implement cookie
authentication. So Browser storage should be the proper direction.
Upvotes: 0