尝试运行最新的热门Blazor应用时出现以下错误!
Unable to resolve service for type 'MyProject.Blazor.Client.ILocalStorageService' while attempting to activate 'MyProject.Blazor.Client.AuthService'.
这是我的Startup.cs,我想我以正确的顺序添加了服务...
using Microsoft.AspNetCore.Components.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Http;
using System.Net.Http;
using Microsoft.AspNetCore.Builder;
using Blazored.LocalStorage;
namespace MyProject.Blazor.Client
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddBlazoredLocalStorage();
services.AddAuthorizationCore();
services.AddScoped<IAuthService, AuthService>();
services.AddScoped<AuthenticationStateProvider, ApiAuthenticationStateProvider>();
// BLAZOR COOKIE Auth Code (begin)
services.Configure<CookiePolicyOptions>(options =>
{
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddAuthentication(
CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie();
// BLAZOR COOKIE Auth Code (end)
}
public void Configure(IComponentsApplicationBuilder app)
{
app.AddComponent<App>("app");
}
}
}
这是我的AuthService:
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using MyProject.Blazor.Shared.Models;
using Microsoft.AspNetCore.Components.Authorization;
using Newtonsoft.Json;
namespace MyProject.Blazor.Client
{
public class AuthService : IAuthService
{
private readonly HttpClient _httpClient;
private readonly AuthenticationStateProvider _authenticationStateProvider;
private readonly ILocalStorageService _localStorage;
public AuthService(HttpClient httpClient,
AuthenticationStateProvider authenticationStateProvider,
ILocalStorageService localStorage)
{
_httpClient = httpClient;
_authenticationStateProvider = authenticationStateProvider;
_localStorage = localStorage;
}
public async Task<RegisterResult> Register(RegisterModel registerModel)
{
string json = JsonConvert.SerializeObject(registerModel, Formatting.Indented);
var stringContent = new StringContent(json);
var result = await _httpClient.PostAsync("api/accounts", stringContent);
var responseString = await result.Content.ReadAsStringAsync();
RegisterResult rr = JsonConvert.DeserializeObject<RegisterResult>(responseString);
return rr ;
}
public async Task<LoginResult> Login(LoginModel loginModel)
{
string json = JsonConvert.SerializeObject(loginModel, Formatting.Indented);
var stringContent = new StringContent(json);
var result = await _httpClient.PostAsync("api/Login", stringContent);
var responseString = await result.Content.ReadAsStringAsync();
LoginResult loginresult = JsonConvert.DeserializeObject<LoginResult>(responseString);
if (loginresult.Successful)
{
await _localStorage.SetItemAsync("authToken", loginresult.Token);
((ApiAuthenticationStateProvider)_authenticationStateProvider).MarkUserAsAuthenticated(loginresult.Token);
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", loginresult.Token);
return loginresult;
}
return loginresult;
}
public async Task Logout()
{
await _localStorage.RemoveItemAsync("authToken");
((ApiAuthenticationStateProvider)_authenticationStateProvider).MarkUserAsLoggedOut();
_httpClient.DefaultRequestHeaders.Authorization = null;
}
}
}
这是我的ApiAuthenticationStateProvider:
using Microsoft.AspNetCore.Components.Authorization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Claims;
using System.Text.Json;
using System.Threading.Tasks;
namespace MyProject.Blazor.Client
{
public class ApiAuthenticationStateProvider : AuthenticationStateProvider
{
private readonly HttpClient _httpClient;
//private readonly ILocalStorageService _localStorage;
private readonly Blazored.LocalStorage.ILocalStorageService _localStorage;
public ApiAuthenticationStateProvider(HttpClient httpClient, Blazored.LocalStorage.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 token)
{
var authenticatedUser = new ClaimsPrincipal(new ClaimsIdentity(ParseClaimsFromJwt(token), "jwt"));
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);
}
}
}
我在这里想念什么?我已经尝试了一天或两天来解决这个问题。我不确定是否存在一些错误的参考,或者可能是错误的。
这是我的.csproj文件:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<OutputType>Exe</OutputType>
<LangVersion>7.3</LangVersion>
<RazorLangVersion>3.0</RazorLangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Blazored.LocalStorage" Version="2.1.1" />
<PackageReference Include="Microsoft.AspNetCore.Authentication" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.Cookies" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Blazor" Version="3.0.0-preview9.19465.2" />
<PackageReference Include="Microsoft.AspNetCore.Blazor.Build" Version="3.0.0-preview9.19465.2" PrivateAssets="all" />
<PackageReference Include="Microsoft.AspNetCore.Blazor.HttpClient" Version="3.0.0-preview9.19465.2" />
<PackageReference Include="Microsoft.AspNetCore.Blazor.DevServer" Version="3.0.0-preview9.19465.2" PrivateAssets="all" />
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="3.0.0" />
<PackageReference Include="Microsoft.AspNetCore.CookiePolicy" Version="2.2.0" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
<PackageReference Include="System.Net.Http.Formatting.Extension" Version="5.2.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Shared\MyProject.Blazor.Shared.csproj" />
</ItemGroup>
</Project>
答案 0 :(得分:0)
请尝试以下设置。
function BackButton({ children })
let history = useHistory()
return (
<button type="button" onClick={() => history.goBack()}>
{children}
</button>
)
}
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddBlazoredLocalStorage();
services.AddAuthorizationCore();
services.AddScoped<IAuthService, AuthService>();
services.AddScoped<ApiAuthenticationStateProvider>();
services.AddScoped<AuthenticationStateProvider>(provider =>
provider.GetRequiredService<ApiAuthenticationStateProvider>());
}
public void Configure(IComponentsApplicationBuilder app)
{
app.AddComponent<App>("app");
}
}
您需要什么???
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
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 void ConfigureServices(IServiceCollection services)
{
services.AddMvc().AddNewtonsoftJson();
services.AddResponseCompression(opts =>
{
opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(
new[] { "application/octet-stream" });
});
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = Configuration["Jwt:Issuer"],
ValidAudience = Configuration["Jwt:Audience"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"]))
};
});
}
// 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.UseClientSideBlazorFiles<Client.Startup>();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
endpoints.MapFallbackToClientSideBlazor<Client.Startup>("index.html");
});
}
}
您不使用Jwt身份验证。查看我的新设置,并调整代码以适合您。
也许您应该升级到HttpClient,Blazor等最新版本。
如果您仍有问题,请不要犹豫,... 如果BlazoredLocalStorage给您带来一些麻烦,请直接通过JSInterop使用Local Storage JavaScript Web Api。这非常简单容易,而且没有痛苦。仅在5分钟内看到MDN ...
希望这对您有帮助...