Вызов асинхронных методов в представлении Blazor

У меня есть клиент Blazor на стороне сервера, и я пытаюсь изменить страницу бритвы MainLayout, выполнив проверку входа. В настоящее время я использую Blazored для сохранения локального хранилища, и в настоящее время я использую, чтобы увидеть, сохранен ли токен, чтобы узнать, вошел ли пользователь в систему, однако я не уверен, как я перевожу это в инструкции if на странице бритвы, потому что это хочет асинхронный метод.

Моя проверка входа в систему довольно проста, как показано ниже.

public async Task<bool> IsLoggedIn()
{
    return await m_localStorage.ContainKeyAsync("token").ConfigureAwait(false);
}

На моей странице Razor я выполняю эту проверку оператора - что, очевидно, не работает, поскольку нет модификатора async

@if (!await AppState.IsLoggedIn()) //Requires async modifier
{
    <a href="Login" target="_blank">Login</a>
}

Я также пробовал сделать это с помощью свойства .Result, но это приводит к возникновению исключения: (System.AggregateException: 'Information: Выполнен неявный метод обработчика, возвращен результат Microsoft.AspNetC)' с внутренним исключением -> NullReferenceException : В экземпляре объекта не задана ссылка на объект.

Но из того, что я вижу, AppState вводится правильно, а локальное хранилище, похоже, правильно вводится в AppState.

@if (!AppState.IsLoggedIn().Result)
{
    <a href="Login" target="_blank">Login</a>
}

Итак, мой вопрос: как правильно подойти к этому, есть ли способ выполнять асинхронные методы на страницах бритвы?


person A.A    schedule 12.10.2019    source источник


Ответы (4)


есть ли способ выполнить асинхронные методы на страницах бритвы?

Нет, в компоненте Razor нельзя использовать ожидание. Это потому, что вы не можете выполнять асинхронную работу как часть отрисовки компонента.

Между прочим, механизм локального хранилища, предоставленный командой Blazor, поддерживает защиту данных и рекомендован для использования Стивом Сандерсоном.

Примечание. В асинхронных методах жизненного цикла компонента выполняется асинхронная работа, поэтому вы можете разработать свой код соответствующим образом, например, вызвав AppState.IsLoggedIn () из OnInitializedAsync и присвоив возвращаемое значение локальной переменной, которая может быть доступны из ваших просмотров.

person Community    schedule 12.10.2019
comment
Какой механизм localstorage, я смог найти только сторонние библиотеки для поддержки локального хранилища, т.е. Кроме того, я не могу вызвать его из метода OnINit, поскольку его блейзер на стороне сервера, и поэтому js interlop еще не готов к этому моменту. - person A.A; 13.10.2019
comment
Вызов AfterRenderAsync, похоже, работает, но мне пришлось вызвать InvokeAsync () для StateChanged, иначе будет выбрано исключение - person A.A; 13.10.2019
comment
Да, метод OnAfterRenderAsync - подходящее место, поскольку этот метод не вызывается, когда ваше приложение предварительно отрисовывается. И вы должны вызвать метод StateHasChanged для повторного рендеринга вашего компонента с новыми данными. - person ; 13.10.2019
comment
См. Эту статью о механизме локального хранилища от команды Blazor: docs.microsoft.com/en-us/aspnet/core/blazor/ - person ; 13.10.2019
comment
На самом деле есть способ, проверьте мой ответ - person Al-Hanash Moataz; 09.05.2020

AsyncComponent.razor

    @typeparam TResult
    @typeparam TInput
    @if (Result != null)
    {
        @DataReadyFragment(Result)
    }
    else if (DataMissingFragment != null)
    {
        @DataMissingFragment
    }
    @code {
        [Parameter] public RenderFragment<TResult> DataReadyFragment { get; set; }
        [Parameter] public RenderFragment DataMissingFragment { get; set; }
        [Parameter] public Func<TInput, Task<TResult>> AsyncOperation { get; set; }
        [Parameter] public TInput Input { get; set; }
        TResult Result { get; set; }

        protected override async Task OnAfterRenderAsync(bool firstRender)
        {
            if(firstRender)
AsyncOperation.Invoke(Input).ContinueWith(t => { Result = t.Result; InvokeAsync(StateHasChanged); });
        }
    }

Использование

<AsyncComponent TResult="User" TInput="string" Input="Pa$$W0rd" AsyncOperation="@AsyncMethodName">
    <DataReadyFragment Context="result">
        @if(result.IsLoggedIn)
         {
           <h3>Logged-In , Username:@result.Name</h3>
         }
         else
         {
          <h3>Wrong Password</h3>
         }
    </DataReadyFragment>
    <DataMissingFragment>
        <h3>Please Login :)</h3>
    </DataMissingFragment>
</AsyncComponent>
person Al-Hanash Moataz    schedule 03.02.2020
comment
Молодец. Но мне пришлось немного изменить: if (firstRender) {await AsyncOperation.Invoke (Input) .ContinueWith (t = ›{Result = t.Result; InvokeAsync (StateHasChanged);}); } Иначе цикл бесконечен .... - person Bronzato; 05.05.2020
comment
@Bronzato да, ты прав, я забыл добавить эту строку кода. Я обновлю свой ответ - person Al-Hanash Moataz; 09.05.2020

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

public partial class FooComponent : IComponent
{
    [Inject]
    public FooService Service { get; set; }

    public string Name => Task.Run(() => Service.GetNameAsync()).GetAwaiter().GetResult();
}

на стороне пользовательского интерфейса просто вызовите параметр Name:

<h3>@Name</h3>
person LazZiya    schedule 14.01.2021

На примере LazZiya у меня сработало. В моем случае событие было не асинхронным, как поддерживается компонентом, а вызовом, который мне требовался await. Используя этот пример, я мог бы вернуть данные из вызова на основе модели.

public string Name => Task.Run(() => Service.GetNameAsync()).GetAwaiter().GetResult();

Я закончил с этим, и это сработало как шарм.

Task<AssessmentResponsesModel> task = Task.Run(() => _IAssessmentResponse.CreateAsync(APIPathD, argsItem, token).GetAwaiter().GetResult());
person WebGeek    schedule 10.03.2021