Asyn c звонки в приложении Blazor зависают навсегда и никогда не дают ошибок - PullRequest
1 голос
/ 20 января 2020

Я пытаюсь вызвать asyn c метод в классе CS, и страница просто зависает. При отладке все кажется работающим нормально до строки await thing.wait.WaitAsync();. После этой строки ни одна другая точка останова не была достигнута (у меня есть несколько точек останова, включая одну на следующей строке), страница выглядит так, как будто она продолжает загружаться, и не появляется сообщение об ошибке / исключении.

ApiClient_Test.razor

@if (myResult == null)
{
    <p><em>Loading...</em></p>
}
else
{
    <p>@myResult</p>
}
@code{
    private string myResult;

    protected override async Task OnInitializedAsync()
    {
    var test = new ApiClient_BlazorTest.ApiClientBlazorTests.ApiClient_TestAsync();
    myResult = test.MyMethod();
    }
}

ApiClientTest.cs

namespace ApiClient_BlazorTest.ApiClientBlazorTests
{
    public class ApiClient_TestAsync : Controller
    {
        public string MyMethod()
        {
            var a = MyAsyncMethod();
            a.Wait();

            return a.Result;
        }

        public async Task<string> MyAsyncMethod()
        {
            var thing = new athing();

            // start a thing that takes 6 seconds
            thing.dothings();
            // await the thing
            await thing.wait.WaitAsync();
            return "ok";
        }

        private class athing
        {
            public SemaphoreSlim wait { get; set; } = new SemaphoreSlim(1);
            public string dothings()
            {
                wait.Wait();
                Task.Run(() => { Thread.Sleep(6000); wait.Release(); });
                return "";
            }
        }   
    }
}

Я запустил тот же код в консольном приложении. Там все прекрасно работало.

Кто-нибудь видел что-то подобное раньше с функциями Blazor и Asyn c?

1 Ответ

3 голосов
/ 20 января 2020

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

Лучшее решение - удалить все вызовы блокировки, т. Е. Использовать await вместо Wait() или Result:

public async Task<string> MyMethodAsync() // was `public string MyMethod()`
{
  var a = MyAsyncMethod();
  // await a; // was `a.Wait();`

  return await a; // was `return a.Result;`
}

я запустил тот же код в консольном приложении. Там все отлично работало.

Консольные приложения не имеют SynchronizationContext, поэтому в этой среде такой тупик не возникает.

...