I understand that a Blazor SSR component's OnInitialized method executes twice if pre-rendering is enabled. I have written the business logic, for e.g., loading all the products from the database, inside the OnInitialized method. How do I prevent the business logic from executing twice? Do I have to keep track of it using a local variable such as IsInitialized = false, and then set it to true once the business logic executes. Does Blazor have a built-in way for detecting this? Or should I move the business logic to a different lifecycle method?
[Update 9/23] Adding the code here for more clarity (implemented @Rena 's 4th answer). Removed all the extraneous code. All components derive from BaseComponent, in which I want to find out the signed-in user. Hence I call the method to get the usercontext in the OnInitialized method, but I want that logic to execute only once. Currently both GetUserContextFromAuthenticationState and GetProductsListFromDatabase are being executed twice. isInitialized is always false.
In the App.razor, I don't specify the render mode, so the application starts in Static Server Render mode. And in the BaseComponent, I specify the Interactive Server Render mode.
BaseComponent.razor
@rendermode InteractiveServer
@code {
private bool isInitialized = false;
protected override async Task OnInitializedAsync()
{
if (!isInitialized)
{
var user = GetUserContextFromAuthenticationState();
isInitialized = true;
}
}
}
Products.razor
@inherits BaseComponent
@code {
private bool isInitialized = false;
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync().ConfigureAwait(false);
if (!isInitialized)
{
var products = GetProductsListFromDatabase();
isInitialized = true;
}
}
}
[Update 9/24] Detecting pre-render using the IHttpContextAccessor.HttpContext works (@Rena answer 2). Marking that as answer.
Though I would like to know why the above code doesn't work. Are the blazor components instantiated twice? That could be the reason why isInitialized is always false. Should I ask this as a separate question? I have spent so much time trying to understand blazor component lifecycle, and still don't get it.
There are several ways we can achieve:
1.As the official document said:
To prevent developer code in OnInitializedAsync from running twice when prerendering, see the Stateful reconnection after prerendering section.
2.You can use the IHttpContextAccessor.HttpContext.Response.HasStarted
property to check whether the application is pre-rendering or not.
@code{
[Inject]
protected IHttpContextAccessor httpContextAccessor { get; set; }
protected override async Task OnInitializedAsync()
{
var isPreRendering = !this.httpContextAccessor.HttpContext.Response.HasStarted;
if (!isPreRendering)
{
//call your service...
}
}
}
The HttpContextAccessor
service should be registered by calling the AddHttpContextAccessor
method in the Program.cs
.
builder.Services.AddHttpContextAccessor();
3.Consider using OnAfterRenderAsync
if you need to perform logic that should only run once after the component is fully rendered. However, be cautious since it runs after every render.
@code{
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
//call your service here
}
}
}