Как мне правильно уведомить пользовательский интерфейс Blazor об изменении моего состояния пользователя?

В настоящее время я изучаю ядро ​​asp.net и Blazor и столкнулся с проблемой с небольшой документацией. У меня есть приложение Blazor на стороне сервера, и я выполняю аутентификацию для использования локального хранилища и ServerAuthenticationStateProvider. Этот код основан на это руководство, вот моя текущая реализация поставщика состояний:

MyAuthenticationStateProvider.cs

namespace BlazorApp
{
    public class MyAuthenticationStateProvider : ServerAuthenticationStateProvider
    {
        private readonly HttpClient _httpClient;
        private readonly ILocalStorageService _localStorage;

        public MyAuthenticationStateProvider(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()));
            }

            var user = new ClaimsPrincipal(new ClaimsIdentity(ParseClaimsFromJwt(savedToken), "jwt"));

            return new AuthenticationState(user);
        }

        public void MarkUserAsAuthenticated(string token)
        {
            var authenticatedUser = new ClaimsPrincipal(new ClaimsIdentity(ParseClaimsFromJwt(token), "jwt"));
            var authState = Task.FromResult(new AuthenticationState(authenticatedUser));
            NotifyAuthenticationStateChanged(authState);

        }

LoginControl.cs

@page "/loginControl"
@inject IAuthService AuthService
@inject NavigationManager NavigationManager

    <AuthorizeView>

        <Authorized>

            <b>Hello, @context.User.Identity.Name!</b>

            <a class="ml-md-auto btn btn-primary"
               href="logout?returnUrl=/"
               target="_top">Logout</a>

        </Authorized>

        <Authorizing>
            <b>Authentication in progress</b>
        </Authorizing>

        <NotAuthorized>

            <input type="text"
                   placeholder="Email"
                   @bind="@email" />

            &nbsp;&nbsp;

            <input type="password"
                   placeholder="Password"
                   @bind="@password" />

            <button class="ml-md-auto btn btn-primary"
                    @onclick="@createSession">
                Login
            </button>

        </NotAuthorized>

    </AuthorizeView>

@code {

    string email = "";

    string password = "";

    async void createSession()
    {

        var loginRequest = new LoginRequest
        {

            Email = email,
            Password = password

        };

        await AuthService.Login(loginRequest);
    }

}

Я ожидал, что после вызова NotifyAuthenticationStateChanged(AuthState) мой пользовательский интерфейс входа в систему обновится и содержимое <Authorized> будет отображаться. Однако мой пользовательский интерфейс по-прежнему показывает <NotAuthorized> содержимое. Я что-то пропустил, что связано с отправкой в ​​основной поток ?? Я новичок во всем этом, но мой наставник упомянул, что что-то связано с этим, возможно, связано с тем, что фоновый поток не сообщает пользовательскому интерфейсу о повторном рендеринге.


person SilenceAmongCrows    schedule 26.11.2019    source источник


Ответы (3)


Действительно просто. Все, что вам нужно сделать, это:

StateHasChanged();

Вчера я только что создал элемент управления входом в систему, так что вот некоторые бонусы, которые вы, возможно, захотите узнать:

Мой контроль входа в систему имеет это:

<Login OnLogin="LoginComplete"></Login>

/// <summary>
/// This method returns the LoginResponse object 
/// </summary>
/// <param name="loginResponse"></param>
private void LoginComplete(LoginResponse loginResponse)
{
    // if the login was successful
    if (loginResponse.Success)
    {
        // Set the player
        player = loginResponse.Player;

        // refresh the UI
        this.StateHasChanged();
    }
}

И под вашим контролем вызвать делегат LoginResponse

// Get the loginResponse
LoginResponse loginResponse = await PlayerService.Login(emailAddress, password);

// if the loginResponse exists
if (NullHelper.Exists(loginResponse))
{
   // set the player
   player = loginResponse.Player;

   // Perform the Login
  await OnLogin.InvokeAsync(loginResponse);
}
person Community    schedule 27.11.2019
comment
Что содержится в вашем ответе на вход? Я не совсем понимаю, что делает строка await OnLogin.InvokeAsync(loginresponse) - person SilenceAmongCrows; 27.11.2019
comment
Вот код для LoginResponse, хотя этот проект еще не готов к клонированию. github.com/DataJuggler/CardCounter/blob/master/ Данные / Это просто класс, который я написал специально для BlackJack, поэтому после входа игрока в систему с помощью элемента управления логином я могу отправить ответ с указанием игрока и его баланса фишек, баланса рынка и т. Д. или неудачный ответ с сообщением. В элементе управления входом в папку компонентов и на странице указателя находится весь работающий код. - person ; 27.11.2019
comment
Чтобы ответить на ваш вопрос, вот код для элемента управления входом: github. com / DataJuggler / CardCounter / blob / master / Components / В строке 69 (на момент написания) метод HandleLogin вызывает службу Player для выполнения входа и отправки ответа обратно на страницу индекса, вы устанавливаете параметр OnLoginComplete в строке 279: [Parameter] public EventCallback ‹LoginResponse› OnLogin {get; установленный; } Затем страница индекса получает ответ. - person ; 27.11.2019
comment
После перехода на Blazor на стороне клиента я столкнулся с аналогичной проблемой и вспомнил этот ответ, который помог. Кажется, я также могу использовать функции задач, и пользовательский интерфейс будет ждать выполнения задачи, а затем обновится соответствующим образом - person SilenceAmongCrows; 29.11.2019

Я решил проблему, перенаправив пользователя с помощью диспетчера навигации и принудительно перенаправив (при этом приложение вынуждено изменить authState). Я сделал это только потому, что StateChanged() не работает.

NaviMngr.NavigateTo("/", true);
person lorenzo    schedule 14.10.2020

Я ошибся, серверный блейзер уже реализует AuthenticationStateProvider, поэтому все, что мне нужно сделать, это реализовать что-то, что устанавливает user.identity.isauthenticated, я использую файлы cookie и токен Jet для этого.

person SilenceAmongCrows    schedule 27.11.2019
comment
Это своего рода ответы, которые дают ключ к разгадке, но они слишком расплывчаты, чтобы что-то сделать. Цитата all I need to do is to implement something that sets the user.identity.isauthenticated Как именно вам это сделать? - person ViRuSTriNiTy; 22.09.2020