Skip to content

'GetAuthenticationStateAsync was called before SetAuthenticationState.' #17442

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Grauenwolf opened this issue Nov 27, 2019 · 12 comments
Closed
Assignees
Labels
area-blazor Includes: Blazor, Razor Components ✔️ Resolution: Answered Resolved because the question asked by the original author has been answered. Status: Resolved
Milestone

Comments

@Grauenwolf
Copy link

Describe the bug

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.

ref: https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.components.server.serverauthenticationstateprovider?view=aspnetcore-3.0

To Reproduce

Inject a ServerAuthenticationStateProvider into a page. Then call 'GetAuthenticationStateAsync in any of its async-events.

Further technical details

<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" />
@javiercn javiercn added the area-blazor Includes: Blazor, Razor Components label Nov 27, 2019
@mkArtakMSFT
Copy link
Member

Thanks for contacting us.
@SteveSandersonMS can you please look into this, thanks!

@Grauenwolf
Copy link
Author

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.

@sven5
Copy link

sven5 commented Dec 12, 2019

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. 😏
I assume someone forgot to register this.

Update: Be aware not to use AddSingleton but use instead AddScoped. This is really important.

@rysep2
Copy link

rysep2 commented Jan 27, 2020

I get the same error when I try to access the AuthenticationStateProvider from any service class.

@Blackleones
Copy link

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.

@nullpainter
Copy link

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.

@sven5
Copy link

sven5 commented Mar 27, 2020

@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.

@Blackleones
Copy link

Blackleones commented Apr 9, 2020

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?

@SteveSandersonMS
Copy link
Member

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!

@SteveSandersonMS SteveSandersonMS added ✔️ Resolution: Answered Resolved because the question asked by the original author has been answered. and removed investigate labels Jun 4, 2020
@ghost ghost added the Status: Resolved label Jun 4, 2020
@ghost
Copy link

ghost commented Jun 5, 2020

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.

@ghost ghost closed this as completed Jun 5, 2020
@eddiepaz
Copy link

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.

@Blackleones Did you ever get this to work? I'm doing basically the same thing and it's still not working.

@TimBurris
Copy link

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();
}

@ghost ghost locked as resolved and limited conversation to collaborators Jul 13, 2020
This issue was closed.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-blazor Includes: Blazor, Razor Components ✔️ Resolution: Answered Resolved because the question asked by the original author has been answered. Status: Resolved
Projects
None yet
Development

No branches or pull requests

10 participants