Search code examples
c#blazorlocal-storage.net-6.0blazor-webassembly

How can I use Blazored.LocalStorage in AuthenticationStateProvider (.Net 6)?


I am trying to use the localStorageService in my CustomAuthStateProvider class so I can create a AuthenticationState based on a key in local storage (just to learn and to practice).

However, when I run my application, I get an error telling me that no suitable constructor can be found for CustomAuthStateProvider. The error makes sense but I don't understand how I can fix it and haven't found much online.

Here is the error:

enter image description here

Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]

Unhandled exception rendering component: A suitable constructor for type 'BlazorBattles.Client.CustomAuthStateProvider' could not be located. Ensure the type is concrete and services are registered for all parameters of a public constructor.

System.InvalidOperationException: A suitable constructor for type 'BlazorBattles.Client.CustomAuthStateProvider' could not be located. Ensure the type is concrete and services are registered for all parameters of a public constructor.

Here is my CustomAuthStateProvider implementing AuthenticationStateProvider:

public class CustomAuthStateProvider : AuthenticationStateProvider
{
    private readonly ILocalStorageService _localStorageService;
    CustomAuthStateProvider(ILocalStorageService localStorageService)
    {
        _localStorageService = localStorageService;
    }

    public override async Task<AuthenticationState> GetAuthenticationStateAsync()
    {
        if (await _localStorageService.GetItemAsync<bool>("isAuthenticated"))
        {
            ClaimsIdentity claimsIdentity = new ClaimsIdentity(new[]
            {
                new Claim(ClaimTypes.Name, "Thomas")
            }, "Test Authentication");

            ClaimsPrincipal user = new ClaimsPrincipal(claimsIdentity);
            AuthenticationState state = new AuthenticationState(user);

            //Tell all the components that the Auth state has changed
            NotifyAuthenticationStateChanged(Task.FromResult(state));
            return (state);
        }

        //This will result in an unauthorised user because it does not have a claims identity
        return (new AuthenticationState(new ClaimsPrincipal()));
    }
}

Here is my Program.cs

using BlazorBattles.Client;
using BlazorBattles.Client.Services;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Blazored.Toast;
using Blazored.LocalStorage;
using Microsoft.AspNetCore.Components.Authorization;

var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.RootComponents.Add<HeadOutlet>("head::after");

builder.Services.AddBlazoredToast();
builder.Services.AddBlazoredLocalStorage();
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
builder.Services.AddScoped<IBananaService, BananaService>();
builder.Services.AddScoped<IUnitService, UnitService>();
builder.Services.AddScoped<AuthenticationStateProvider, CustomAuthStateProvider>();
builder.Services.AddOptions();
builder.Services.AddAuthorizationCore();

await builder.Build().RunAsync();

I am using V4.3.0 for Blazored.LocalStorage and V6 for Microsoft.AspNetCore.Components.Authorization

Thanks.

It works as expected when I remove the constructor and references to LocalStorage but when I try to inject LocalStorage to use it then I get the error. I'm not sure how to make use of the constrctor correctly in this specific case?

Update: The solution to my problem here is to add the public keyword for the constructor


Solution

  • The issue with my code above is that I had missed out the public keyword in my constructor and now it works as expected. A huge thank you to everyone who commented on my post and provided potential solutions, I appreciate the time you took to help me out!

    Original code:

    CustomAuthStateProvider(ILocalStorageService localStorageService)
    {
        _localStorageService = localStorageService;
    }
    

    Updated code:

    public CustomAuthStateProvider(ILocalStorageService localStorageService)
    {
        _localStorageService = localStorageService;
    }