C
C#7mo ago
Lukaa

Proper way to do per user state management in Blazor with Identity

Hi. I am attempting to have state management with blazor & identity. So basically I want to acquire the current user in the ManageLayout and then reuse the data in navmenu or in @body. I was thinking of just passing them as parameters, but you need some kind of synchronization due to asynchronous user retrieval. this is my state code :
internal sealed class AccountDataState
{
public string? Username { get; private set; }
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly UserManager<ApplicationUser> _userManager;
private readonly IdentityUserAccessor _userAccessor;

public AccountDataState(IHttpContextAccessor httpContextAccessor, UserManager<ApplicationUser> userManager, IdentityUserAccessor userAccessor)
{
_httpContextAccessor = httpContextAccessor;
_userManager = userManager;
_userAccessor = userAccessor;
}

public event Action OnChange;
public async Task InitializeAsync()
{
var user = await _userAccessor.GetRequiredUserAsync(_httpContextAccessor.HttpContext);
Username = await _userManager.GetUserNameAsync(user);
NotifyStateChanged();
}
private void NotifyStateChanged() => OnChange?.Invoke();
}
internal sealed class AccountDataState
{
public string? Username { get; private set; }
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly UserManager<ApplicationUser> _userManager;
private readonly IdentityUserAccessor _userAccessor;

public AccountDataState(IHttpContextAccessor httpContextAccessor, UserManager<ApplicationUser> userManager, IdentityUserAccessor userAccessor)
{
_httpContextAccessor = httpContextAccessor;
_userManager = userManager;
_userAccessor = userAccessor;
}

public event Action OnChange;
public async Task InitializeAsync()
{
var user = await _userAccessor.GetRequiredUserAsync(_httpContextAccessor.HttpContext);
Username = await _userManager.GetUserNameAsync(user);
NotifyStateChanged();
}
private void NotifyStateChanged() => OnChange?.Invoke();
}
Currently this doesn't work in another component, when Username is initialized it doesn't really notify all components even though the state is injected, I assume that's due to service being Scoped. How is the conventional way to approach this issue? ManageLayout.razor :
protected override async void OnInitialized()
{
State.OnChange += StateHasChanged;
await State.InitializeAsync();
}
protected override async void OnInitialized()
{
State.OnChange += StateHasChanged;
await State.InitializeAsync();
}
Index.razor
<h1>@username</h1>
@code{
protected override async Task OnInitializedAsync()
{
username = State.Username;
}
<h1>@username</h1>
@code{
protected override async Task OnInitializedAsync()
{
username = State.Username;
}
1 Reply
Lukaa
LukaaOP7mo ago
even with this I get cannot call method of a disposed class. but IdentityUserAccessor is scoped.. im confused
<div class="flex-body">
@if (Username == null)
{
<p1>Loading</p1>
}

else
{
<CascadingValue Value="@Username" Name="username">
<ManageNavMenu />
@Body
</CascadingValue>
}

</div>


@code {
protected string? Username;
private ApplicationUser User = default!;

[CascadingParameter]
private HttpContext HttpContext { get; set; } = default!;

protected override async void OnInitialized()
{
var user = await UserAccessor.GetRequiredUserAsync(HttpContext);
Username = await UserManager.GetUserNameAsync(user);
}
}
protected override async void OnInitialized()
{
var user = await UserAccessor.GetRequiredUserAsync(HttpContext);
Username = await UserManager.GetUserNameAsync(user);
}
<div class="flex-body">
@if (Username == null)
{
<p1>Loading</p1>
}

else
{
<CascadingValue Value="@Username" Name="username">
<ManageNavMenu />
@Body
</CascadingValue>
}

</div>


@code {
protected string? Username;
private ApplicationUser User = default!;

[CascadingParameter]
private HttpContext HttpContext { get; set; } = default!;

protected override async void OnInitialized()
{
var user = await UserAccessor.GetRequiredUserAsync(HttpContext);
Username = await UserManager.GetUserNameAsync(user);
}
}
protected override async void OnInitialized()
{
var user = await UserAccessor.GetRequiredUserAsync(HttpContext);
Username = await UserManager.GetUserNameAsync(user);
}
Want results from more Discord servers?
Add your server