首页 > 解决方案 > Blazored.LocalStorage.ILocalStorageService.GetItemAsync (字符串))

问题描述

我是 .NET6 的新手,我在 .NET 6 中创建了 blazor WASM 应用程序。它的身份验证部分是 JWT 身份验证。当我要将令牌存储到本地存储中时,会发生以下错误。

blazor.webassembly.js:1 System.AggregateException:发生一个或多个错误。(找不到方法:System.Threading.Tasks.ValueTask 1<!!0> Blazored.LocalStorage.ILocalStorageService.GetItemAsync<!0>(string)) ---> System.MissingMethodException: Method not found: System.Threading.Tasks.ValueTask1<!!0>

Blazored.LocalStorage.ILocalStorageService.GetItemAsync<!0>(string) at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[d__8](d__8& stateMachine) in System.Private.CoreLib.dll:token 0x600454a+0x28 at Infrastructure.Manager.Preferences .ClientPreferenceManager.GetPreference() in Infrastructure.dll:token 0x600004d+0xc at BlSls.Client.Program.Main(String[] args) in BlSls\Client\Program.cs:line 36 --- 内部异常堆栈跟踪结束 - --

我的程序.cs

public static async Task Main(string[] args)
        {
            var builder = WebAssemblyHostBuilder.CreateDefault(args).AddRootComponents().AddClientServices();

            var host = builder.Build();


            var storageService = host.Services.GetRequiredService<ClientPreferenceManager>();

            if (storageService != null)
            {
                CultureInfo culture;
                var preference = await storageService.GetPreference() as ClientPreference;

      
            }



            builder.Services.AddMudServices();
            builder.Services.AddTransient<ILocalItemStore,LocalItemStore>();
            builder.Services.AddSingleton<IDataConnect, DataConnect>();
            builder.Services.AddScoped<Service.InterData>();


            await builder.Build().RunAsync();
        }

ILocalStorageService.cs

public interface ILocalStorageService
    {
        event EventHandler<ChangingEventArgs> Changing;
        event EventHandler<ChangedEventArgs> Changed;

        ValueTask ClearAsync();
        ValueTask<bool> ContainKeyAsync(string key);
        ValueTask<string> GetItemAsStringAsync(string key);
        ValueTask<T> GetItemAsync<T>(string key);
        ValueTask<string> KeyAsync(int index);
        ValueTask<int> LengthAsync();
        ValueTask RemoveItemAsync(string key);
        ValueTask SetItemAsync<T>(string key, T data);
    }

import.razor 中所需的 DI

@inject BL10StateProvider _stateProvider
@inject IAuthenticationManager _authenticationManager

登录.razor

<div class="d-block">
            <EditForm Model="@_tokenModel" OnValidSubmit="SubmitAsync">

                <DataAnnotationsValidator />
                <div class="@(f ? "invalid-box":"user-box")">
                    <InputText placeholder="Username" @bind-Value="_tokenModel.UserName" />
                    <ValidationMessage For="() => _tokenModel.UserName" />
                    @*<label class="body-default">Email</label>*@
                </div>
                <div class="@(f ? "invalid-box":"user-box")">
                    <InputText type="password" placeholder="Password" @bind-Value="_tokenModel.Password" />
                    <ValidationMessage For="() => _tokenModel.Password" />
                    @*<label class="body-default">Password</label>*@
                </div>


                <div>
                    <button type="submit" class="btn-block login-btn button-text"> Sign In</button>
                </div>
            </EditForm>
        </div>

登录.razor.cs

public partial class Login
    {

        bool f = false;
        private TokenRequest _tokenModel = new();



        protected override async Task OnInitializedAsync()
        {
            var state = await _stateProvider.GetAuthenticationStateAsync();
            if (state != new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity())))
            {
                _navigationManager.NavigateTo("/login");
            }
            await Task.FromResult(0);
        }

        private async Task SubmitAsync()
        {
            var result = await _authenticationManager.Login(_tokenModel);

            if (result.Succeeded)
            {
                f = false;
                _navigationManager.NavigateTo("/CompanySelection", true);
            }
            else
            {
                _tokenModel.Messaage = "UserName Or Password Incorrect";
                f = true;
            }
        }


    }

BL10StateProvider.cs

public class BL10StateProvider {

public override async Task<AuthenticationState> GetAuthenticationStateAsync()
        {
            var savedToken = await _localStorage.GetItemAsync<string>(StorageConstants.Local.AuthToken);
            if (string.IsNullOrWhiteSpace(savedToken))
            {
                return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()));
            }
            _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", savedToken);
            var state = new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity(GetClaimsFromJwt(savedToken), "jwt")));
            AuthenticationStateUser = state.User;
           
            return state;
        }

}

身份验证管理器.cs

public class AuthenticationManager{

        public async Task<IResult> Login(TokenRequest model)
        {
           
            HttpResponseMessage response=null;
            try
            {
                using (var httpClient = new HttpClient())
                {
                    using (var request = new HttpRequestMessage(new HttpMethod("POST"), TokenEndpoints.Authenticate))
                    {
                        request.Headers.TryAddWithoutValidation("Timestamp", DateTime.Now.Ticks.ToString());                       
                        request.Content = JsonContent.Create(model);
                        request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
                        response = await httpClient.SendAsync(request);
                    }
                }
            }
            catch (Exception exp)
            {
                model.Messaage = "Login Falied";
                model.IsTokenRequestFailed = true;
                return await Result.FailAsync("Server Or API Host Not found");
            }
            //HttpRequestMessage req = new HttpRequestMessage();
            //req.Method = HttpMethod.Post;
            //req.RequestUri = TokenEndpoints.Authenticate;
            //req.
            ////var response = await _httpClient.PostAsJsonAsync(TokenEndpoints.Authenticate, model);
            
            // var response = await _httpClient.PostAsJsonAsync()
            string responseBody = await response.Content.ReadAsStringAsync();
            TokenResponse tokenRequest = JsonConvert.DeserializeObject<TokenResponse>(responseBody);
            //var result = await response.ToResult<TokenResponse>();
            if (tokenRequest.IsSuccess)
            {
                model.IsTokenRequestFailed = false;
                model.Messaage = "Login Successful";
                var token = tokenRequest.Token;
                var refreshToken = tokenRequest.RefreshToken;
                var userImageURL = tokenRequest.UserImageURL;
                await _localStorage.SetItemAsync(StorageConstants.Local.AuthToken, token);
                await _localStorage.SetItemAsync(StorageConstants.Local.RefreshToken, refreshToken);
              
                if (!string.IsNullOrEmpty(userImageURL))
                {
                    await _localStorage.SetItemAsync(StorageConstants.Local.UserImageURL, userImageURL);
                }
                ((BL10StateProvider)this._authenticationStateProvider).MarkUserAsAuthenticated(model.UserName);
                _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
                return await Result.SuccessAsync();
            }
            else
            {
                model.Messaage = "Login Falied";
                model.IsTokenRequestFailed = true ;
                return await Result.FailAsync(tokenRequest.Messages);
            }
        }
}

请使用上面的代码示例帮助我解决这个问题。

标签: jwtlocal-storageblazorwebassembly

解决方案


当您在 Main() 中时,在 .RunAsync() 之前,JavaScript 尚未加载。

错误在这一行:

var preference = await storageService.GetPreference() as ClientPreference;

无论您对此有什么逻辑,都必须稍后执行。

一个可能的位置是在 App 组件中,在 OnAfterRenderAsync(true) 中:

protected override async Task OnAfterRenderAsync(bool firstRender)
{
    if (firstRender)
    {
       var preference = await storageService.GetPreference() as ClientPreference;     

       ...
    }
}

但请注意,在您设置该首选项之前,您的第一页可能已经在初始化和渲染。


推荐阅读