GetAuthenticationStateAsync throws an InvalidOperationException with the message:
'GetAuthenticationStateAsync was called before SetAuthenticationState.'
I do not know if this is an actual bug or just a lack of documentation on its correct use.
Inject a ServerAuthenticationStateProvider
into a page. Then call 'GetAuthenticationStateAsync
in any of its async-events.
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="3.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="3.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="3.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="3.0.0" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="3.0.0" />
Thanks for contacting us.
@SteveSandersonMS can you please look into this, thanks!
I switched to using [CascadingParameter] Task<AuthenticationState> AuthenticationState { get; set; }
instead. If that's actually the right way to do it then a simple note in the GetAuthenticationStateAsync
docs would be sufficient.
You'll have to manually register the AuthenticationStateProvider
in ConfigureServices:
services.AddScoped<AuthenticationStateProvider, ServerAuthenticationStateProvider>();
This is a little weird as I expected that this service is already registered behind the scenes. :smirk:
I assume someone forgot to register this.
Update: Be aware not to use AddSingleton
but use instead AddScoped
. This is really important.
I get the same error when I try to access the AuthenticationStateProvider
from _any_ service class.
I have the same problem.
I have a service called CurrentUserService
with the goal of retrieving the current user. Each time anyone calls dbContext SaveChangesAsync()
then I try to retrieve the current user through CurrentUserService
but then I get the exception.
my code
public interface ICurrentUserService
{
Task<string> GetUserId();
}
public class CurrentUserService : ICurrentUserService
{
private readonly AuthenticationStateProvider _authenticationStateProvider;
public CurrentUserService(AuthenticationStateProvider authenticationStateProvider)
{
_authenticationStateProvider = authenticationStateProvider;
}
public async Task<string> GetUserId()
{
var authState = await _authenticationStateProvider.GetAuthenticationStateAsync();
var user = authState.User;
if (user.Identity.IsAuthenticated)
{
return user.Identity.Name;
}
else
{
return null;
}
}
}
my dbContext snapshot
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>, IApplicationDbContext
{
private readonly ICurrentUserService _currentUserService;
/* ... */
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options, ICurrentUserService currentUserService) : base(options)
{
_currentUserService = currentUserService;
}
public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = new CancellationToken())
{
var userId = await _currentUserService.GetUserId();
foreach (var entry in ChangeTracker.Entries<AuditableEntity>())
{
switch (entry.State)
{
case EntityState.Added:
entry.Entity.CreatedBy = userId;
entry.Entity.Created = DateTimeOffset.Now;
break;
case EntityState.Modified:
entry.Entity.LastModifiedBy = userId;
entry.Entity.LastModified = DateTimeOffset.Now;
break;
}
}
return await base.SaveChangesAsync(cancellationToken);
}
/* ... */
}
I've noticed that when this service is called from a Blazor page then it works.
You'll have to manually register the
AuthenticationStateProvider
in ConfigureServices:
services.AddSingleton<AuthenticationStateProvider, ServerAuthenticationStateProvider>();
I presume this is intended to be AddScoped
, @sven5? When I naively copied and pasted this registration, I ended up with one user's session receiving the other session's user details.
@nullpainter
Oh yes you could be right about this.
However, it seems that this is no longer needed. I'm currently working on a new Blazor project using .NET Core 3.1.2 - I didn't explicitly register the AuthenticationStateProvider
and it's working.
I've noticed that if I change services.AddScoped<AuthenticationStateProvider, RevalidatingIdentityAuthenticationStateProvider<IdentityUser>>();
to services.AddSingleton<AuthenticationStateProvider, RevalidatingIdentityAuthenticationStateProvider<IdentityUser>>();
then I don't have any exception, but I don't think this is a good solution. Are there other solutions?
Inject a ServerAuthenticationStateProvider into a page.
This is the problem. Don't do that, because you'll just receive an uninitialized instance.
You need to use the instance provided by the framework, which has been initialized. To get that, inject an AuthenticationStateProvider
instead of ServerAuthenticationStateProvider
.
For anyone else posting here, your issues may be different, since maybe you were not trying to inject ServerAuthenticationStateProvider
. If you still have trouble, could you please post a separate issue with repro steps for your scenario? Thanks!
This issue has been resolved and has not had any activity for 1 day. It will be closed for housekeeping purposes.
See our Issue Management Policies for more information.
I have the same problem.
I have a service called
CurrentUserService
with the goal of retrieving the current user. Each time anyone calls dbContextSaveChangesAsync()
then I try to retrieve the current user throughCurrentUserService
but then I get the exception.
@Blackleones Did you ever get this to work? I'm doing basically the same thing and it's still not working.
Much like @eddiepaz , i'm still exeriencing the same issue. i think for me it's because i'm using custom Middleware and utilizing IServiceProvider with CreateScope to created a Scoped instance of my User provider.
the error can be demonstrated with the following (serviceProvider is an injected IServiceProvider):
using (var serviceScope = serviceProvider.CreateScope())
{
var service = serviceScope.ServiceProvider.GetRequiredService<AuthenticationStateProvider>();
var state= await service.GetAuthenticationStateAsync();
}