Is using .NET HttpClient without Async is bad practice?

Viewed 140

I am working with ASP.NET Core MVC (.NET 6), had read many example about PostAsJsonAsync() method work in async/await, and doesn't recommend use the Result property of the task because it is blocking.

I am curious is it really that bad if running ASP.NET server-side application?

For example - web Controller

public IActionResult Authorized([Required] string code)
{
   if (ModelState.IsValid)
    {
        var payLoad = (dynamic)new JsonObject();
        payLoad.code = code;
        var content = new StringContent(payLoad.ToString(), Encoding.UTF8, "application/json");

        using HttpClient httpClient = new HttpClient();
        
        var result = httpClient.PostAsJsonAsync("https://www.apiserver.com", content).Result;
        string responseBody = result.Content.ReadAsStringAsync().Result;

    }
    return View();
}

The code is clean and straight forward. If I change to Async/Await

var response = await client.SendAsync(request);
var content = await response.Content.ReadAsStringAsync();

And I have to change the IActionResult to async Task<IActionResult>, Had do a load test on 100 requests per minutes to compare Sync or Async, it seem not much performance gain, so what is beneficial? If .Result is so bad, why Microsoft not obsolete this?

1 Answers

Yes, definitely don't use .Result.

Blocking asynchronous execution by using things like .Result or Task.Wait can lead to thread pool starvation and degraded response times. This is a common issue I see people doing in ASP.NET Core apps.

By using asynchronous code correctly, your app will be able to process many requests simultaneously. A small pool of threads can handle thousands of concurrent requests by not waiting on blocking calls.

So now your app will handle a lot more requests without blocking any threads, and not forcing threads to wait (and do nothing) for x seconds for I/O work to complete. All of these leads to improved scalability of your application.

Async/await code is still pretty clean. It allows asynchronous code to look like synchronous code without the need for callbacks, etc.

And like someone in the comments has already mentioned, there are cases where you cannot awaits tasks (mostly legacy code), so the Result property comes in handy. But even in legacy code, if you cannot await a task and you have the option to use either an asynchronous method or a synchronous method, use the synchronous version.

Related