我如何解决此Blazor客户端本地存储错误:无法为类型解析服务

问题描述 投票:0回答:1

[在尝试运行新的热门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>
service dependency-injection blazor blazor-client-side
1个回答
0
投票
Client.Startup

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

Server.Startup

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"); }); } } 您需要什么???
 // 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)

您不使用Jwt身份验证。查看我的新设置,并调整代码以适合您。

也许您应该升级到最新版本,例如HttpClient,Blazor等。

[如果您仍有问题,请随时询问...如果BlazoredLocalStorage给您带来一些麻烦,请直接通过JSInterop使用Local Storage JavaScript Web Api。这非常简单容易,而且没有痛苦。为此,请参阅MDN ...仅5分钟...

希望这有帮助...

© www.soinside.com 2019 - 2024. All rights reserved.