Reputation: 6246
I'm creating a new website with Blazor and the NET8 framework using the boilerplate from Visual Studio 2022 Preview. The source code of this test is on GitHub.
As in my other post, I have already changed the ApplicationUser
adding a new properties such as
public string? FirstName { get; set; }
public string? LastName { get; set; }
Now, in the file Index.razor under Components > Pages > Account > Manage, I like to allow the users to change or add those values.
The important thing is that on the left side, in the _NavManu.razor, there is a place where I display the username or the FirstName
like that
<AuthorizeView>
<Authorized>
<div class="nav-item px-3">
<NavLink class="nav-link" href="/Account/Manage">
<span class="bi bi-person-fill" aria-hidden="true"></span>
@(usermanager.GetUserAsync(context.User).Result.FirstName ??
context.User.Identity?.Name)
</NavLink>
</div>
</Authorized>
</AuthorizeView>
in the NavMenu.razor I added at the top of the page
@inject UserManager<ApplicationUser> usermanager
Now, when I try to save a new value for the FirstName for example, I invoke
if (Input.FirstName != _firstname)
{
_user.FirstName = Input.FirstName;
await UserManager.UpdateAsync(_user);
}
Immediately, I get an error in the NavMenu.razor
InvalidOperationException: A second operation was started on this context instance before a previous operation completed. This is usually caused by different threads concurrently using the same instance of DbContext. For more information on how to avoid threading issues with DbContext, see https://go.microsoft.com/fwlink/?linkid=2097913.
The same code is working in the container of a NET7 Blazor application without issues.
Is there a way that I can fix it?
After the message from H H, I added in the NavMenu.razor this code
@code {
private string? Username;
protected override async Task OnInitializedAsync()
{
var authState = await
AuthenticationStateProvider.GetAuthenticationStateAsync();
var user = authState.User;
if (user.Identity.IsAuthenticated)
{
var fulldetails = await usermanager.GetUserAsync(user);
Username = fulldetails.FirstName ?? user.Identity.Name;
}
}
}
With this, I can save an update as I can see here.
but if I click on any link, immediately I get this error
InvalidOperationException: A second operation was started on this context instance before a previous operation completed. This is usually caused by different threads concurrently using the same instance of DbContext. For more information on how to avoid threading issues with DbContext, see https://go.microsoft.com/fwlink/?linkid=2097913. Microsoft.EntityFrameworkCore.Infrastructure.Internal.ConcurrencyDetector.EnterCriticalSection()
Upvotes: 1
Views: 326
Reputation: 273464
The main problem probably is @(usermanager.GetUserAsync(context.User).Result.FirstName ...
The (generated) BuildRenderTree method is not async and using .Result
is asking for deadlocks.
When you await
inside your SaveAsync()
method a Render will happen (*) and that is where the conflict occurs.
The solution is to establish the userName in OnInitalizedAsync , not in the markup.
(*) I have to check that for SSR
Upvotes: 1