Table of Contents
Why is IHttpContextAccessor -or- HttpContext sometimes null on Blazor Server?
The IHttpContextAccessor on Blazor Server is only available on the first Http request when loading a Blazor Server application. After that, all connections to the server is handled via SignalR. Your HttpContext will most likely be null after this. This may be unfamiliar to you if you’re coming from a MVC/Razor Pages background.
You should persist the HttpContext information via a cascading parameter throughout the application life cycle.
In this article we’ll show you how to do that.
Specifics From Microsoft
Don't use IHttpContextAccessor/HttpContext directly or indirectly in the Razor components of Blazor Server apps. Blazor apps run outside of the ASP.NET Core pipeline context. The HttpContext isn't guaranteed to be available within the IHttpContextAccessor, and HttpContext isn't guaranteed to hold the context that started the Blazor app.
Microsoft
A critical aspect of Blazor Server security is that the user attached to a given circuit might become updated at some point after the Blazor circuit is established but the IHttpContextAccessor isn't updated.
Microsoft
Shared state Blazor server apps live in server memory, and multiple app sessions are hosted within the same process. For each app session, Blazor starts a circuit with its own dependency injection container scope, thus scoped services are unique per Blazor session. Warning, we don't recommend apps on the same server share state using singleton services unless extreme care is taken, as this can introduce security vulnerabilities, such as leaking user state across circuits.
Microsoft
Okay, so how do you fix this?
The solution is fairly straight forward but has some nuance, see below:
Create a User model
UserModel.cs
public class UserModel
{
public string UserName { get; set; }
//Add whatever additional properties you may need here
}
Create a User Repository
IUserRepository.cs & UserRepository.cs
public interface IUserRepository
{
public UserModel GetLoggedInUser();
}
public class UserRepository : IUserRepository
{
private readonly IHttpContextAccessor _httpContextAccessor;
public UserRepository(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor
}
public UserModel GetLoggedInUser()
{
UserModel user = new();
user.UserName = _httpContextAccessor.HttpContext.User.Identity.Name;
return user;
}
}
Wire Up Dependencies
Program.cs
public class Program
{
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpContextAccessor();
builder.Services.AddScoped();
var app = builder.Build()
.
.
.
app.Run();
}
The Scoped dependency ensures the IUserRepository is not shared among users. Read more here
Wire up cascading parameter
_Host.cshtml
@inject IUserRepository User
@{
UserModel UserObject = await User.GetLoggedInUser();
if(UserObject != null)
{
.
.
//param-UserObject = "@UserObject" is key for persisting the user object as a cascading parameter
.
.
}
else
{
Invalid user
}
}
App.razor
Not found
Sorry, there's nothing at this address.
@code
{
[Parameter]
public UserModel UserObject { get; set; }
}
Accessing your UserObject in a custom component
MyCustomComponent.razor
@if(User is not null)
{
Hi! @User.UserName
}
@code
{
[CascadingParameter]
public UserModel User { get; set; }
}
You can see the UserObject is now exposed via cascading parameter. You can access this object anywhere throughout the Blazor Server application.
I hope this tutorial was helpful for you!
Want to learn more?
Why Is IHttpContextAccessor/HttpContext null on Blazor Server? Here’s how to fix it!
Table of Contents Why is IHttpContextAccessor -or- HttpContext sometimes null on Blazor Server? The IHttpContextAccessor on Blazor Server is only available on the first Http request when loading a Blazor Server application. After that, all…
Read moreIHttpClientFactory vs. HttpClient
Why should you use IHttpClientFactory The main reason to use IHttpClientFactoryinstead of HttpClient directly is to manage the life cycle of HttpClient instances. HttpClient was designed to be instantiated once and reused throughout the application…
Read moreHow can I dynamically render components using MudBlazor radio buttons?
You need to have a MudRadioGroup to contain your MudRadio buttons. On the MudRadioGroup you have the @bind-SelectedOption event callback exposed. You can set a switch statement on that to dynamically render your other components. Parent Component: TestComponent.razor Sample Project https://try.mudblazor.com/snippet/wOmRucPSpMDbtnAw
Read more