Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Async calls in blazor app hang forever and never error

I am trying to call an async method in a cs class and the page just freezes. When debugging this, everything seems to run fine till the await thing.wait.WaitAsync(); line. After that line no other breakpoint gets hit (I have a bunch of breakpoints around, including one on the next line), the page looks like it keeps loading and no error/exception message pops up.

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

I ran the same code on a console app. Everything worked perfectly fine there.

Had anyone seen something like this before with blazor and async functions?

like image 973
Ioana Georgiana Avatar asked Oct 25 '25 03:10

Ioana Georgiana


1 Answers

The Blazor render has a SynchronizationContext, so blocking on asynchronous code can cause a deadlock.

The best solution is to remove all blocking calls - i.e., use await instead of Wait() or 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;`
}

I ran the same code on a console app. Everything worked perfectly fine there.

Console applications do not have a SynchronizationContext, so this deadlock does not happen in that environment.

like image 117
Stephen Cleary Avatar answered Oct 26 '25 17:10

Stephen Cleary