I cannot understand why do i keep getting this exception. I try to secure a Blazor WebAssembly
blazor.webassembly.js:1 WASM: System.MissingMethodException: Default constructor not found for type Microsoft.AspNetCore.Components.Authorization.AuthorizeRouteView
app.razor
<Router AppAssembly="@typeof(Program).Assembly">
<Found Context="routeData">
<AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
</Found>
<NotFound>
<CascadingAuthenticationState>
<LayoutView Layout="@typeof(MainLayout)">
<p>Sorry, there's nothing at this address.</p>
</LayoutView>
</CascadingAuthenticationState>
</NotFound>
</Router>
this is the client program.cs
public class Program
{
public static async Task Main(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("app");
builder.Services.AddScoped<AuthenticationStateProvider, ApiAuthenticationStateProvider>();
builder.Services.AddAuthorizationCore(options => { });
await builder.Build().RunAsync();
}
}
the custom auth state provider
public class ApiAuthenticationStateProvider : AuthenticationStateProvider
{
private readonly HttpClient _httpClient;
private readonly ILocalStorageService _localStorage;
public ApiAuthenticationStateProvider(HttpClient httpClient, ILocalStorageService localStorage)
{
_httpClient = httpClient;
_localStorage = localStorage;
}
public override async Task<AuthenticationState> GetAuthenticationStateAsync()
{
var savedToken = await _localStorage.GetItemAsync<string>("authToken");
if (string.IsNullOrWhiteSpace(savedToken))
{
return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()));
}
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", savedToken);
return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity(ParseClaimsFromJwt(savedToken), "jwt")));
}
public void MarkUserAsAuthenticated(string email)
{
ClaimsPrincipal authenticatedUser = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, email) }, "apiauth"));
var authState = Task.FromResult(new AuthenticationState(authenticatedUser));
NotifyAuthenticationStateChanged(authState);
}
public void MarkUserAsLoggedOut()
{
var anonymousUser = new ClaimsPrincipal(new ClaimsIdentity());
var authState = Task.FromResult(new AuthenticationState(anonymousUser));
NotifyAuthenticationStateChanged(authState);
}
private IEnumerable<Claim> ParseClaimsFromJwt(string jwt)
{
var claims = new List<Claim>();
var payload = jwt.Split('.')[1];
var jsonBytes = ParseBase64WithoutPadding(payload);
var keyValuePairs = JsonSerializer.Deserialize<Dictionary<string, object>>(jsonBytes);
keyValuePairs.TryGetValue(ClaimTypes.Role, out object roles);
if (roles != null)
{
if (roles.ToString().Trim().StartsWith("["))
{
var parsedRoles = JsonSerializer.Deserialize<string[]>(roles.ToString());
foreach (var parsedRole in parsedRoles)
{
claims.Add(new Claim(ClaimTypes.Role, parsedRole));
}
}
else
{
claims.Add(new Claim(ClaimTypes.Role, roles.ToString()));
}
keyValuePairs.Remove(ClaimTypes.Role);
}
claims.AddRange(keyValuePairs.Select(kvp => new Claim(kvp.Key, kvp.Value.ToString())));
return claims;
}
private byte[] ParseBase64WithoutPadding(string base64)
{
switch (base64.Length % 4)
{
case 2: base64 += "=="; break;
case 3: base64 += "="; break;
}
return Convert.FromBase64String(base64);
}
}
}
the server startup.cs
public class Startup
{
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = Configuration["JwtIssuer"],
ValidAudience = Configuration["JwtAudience"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["JwtSecurityKey"]))
};
});
services.AddBlazoredLocalStorage();
services.AddAuthorizationCore();
services.AddScoped<AuthenticationStateProvider, ApiAuthenticationStateProvider>();
services.AddScoped<IAuthService, AuthService>();
services.AddMvc();
services.AddResponseCompression(opts =>
{
opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(
new[] { "application/octet-stream" });
});
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<IdentityUser>()
.AddEntityFrameworkStores<ApplicationDbContext>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseResponseCompression();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseBlazorDebugging();
}
app.UseStaticFiles();
app.UseClientSideBlazorFiles<Client.Program>();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
endpoints.MapFallbackToClientSideBlazor<Client.Program>("index.html");
});
}
}
The Blazor framework provides built-in input components to receive and validate user input. Inputs are validated when they're changed and when a form is submitted. Available input components are shown in the following table. Rendered as… For more information on the InputFile component, see ASP.NET Core Blazor file uploads.
Blazor Server apps don't include an HttpClient configured as a service by default. Provide an HttpClient to a Blazor Server app. For more information, see Call a web API in an ASP.NET Core Blazor app. An HttpClient is registered as a scoped service, not singleton.
Framework-registered services can be injected directly into components of Blazor apps. Blazor apps define and register custom services and make them available throughout the app via DI. The services shown in the following table are commonly used in Blazor apps.
BlazorAppClient5 C:\Users\Пользователь\sourceepos\BlazorAppClient5\BlazorAppClient5_Imports.razor I second this one. I was using AuthenticationStateProvider fine on P8 yesterday morning. P9 broke it. Creating client-side and server-side default apps and adding an @import to the MainLayout.razor file.
Add @using Microsoft.AspNetCore.Components.Authorization
at the top of the App.razor file.
Add services for options and authorization to Program.Main (Client-side):
builder.Services.AddOptions();
builder.Services.AddAuthorizationCore();
Note: The following (Client-side):
services.AddBlazoredLocalStorage();
services.AddAuthorizationCore();
services.AddScoped<AuthenticationStateProvider,
ApiAuthenticationStateProvider>();
services.AddScoped<IAuthService, AuthService>();
Belongs in the client, not in the server, though at the end of the day its the same configuration...
Note: The following (Client-side):
services.AddScoped<AuthenticationStateProvider,
ApiAuthenticationStateProvider>();
Should be (Client-side):
services.AddScoped<ApiAuthenticationStateProvider>();
services.AddScoped<AuthenticationStateProvider>(provider => provider.GetRequiredService<ApiAuthenticationStateProvider>());
You should pay attention to order in the Startup class
Update:
Disabling the linker, as I've suggested in a comment below seems to be working. However, this should be a temporary solution. This is how you disable the linker: <BlazorLinkOnBuild>false</BlazorLinkOnBuild>
By disabling the linker, you prevent the removal of unused or un-referenced code, which may be the cause of the error... And by enabling the linker, you allow this. However, this code:
builder.Services.AddOptions();
builder.Services.AddAuthorizationCore();
should have prevented the linker from stripping off un-referenced logic. Still better, adding a custom AuthenticationStateProvider implementation in the Program class:
builder.Services.AddScoped<AuthenticationStateProvider,
ApiAuthenticationStateProvider>();
should have fixed this issue. Did you do that like that ?
Once again, disabling the linker is a temporary solution.
I had this problem. It went away when I installed Microsoft.AspNetCore.Components.Authorization
from NuGet. The @using Microsoft.AspNetCore.Components.Authorization
directive does not give any visual clues in Visual Studio that the package is missing
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With