Search code examples
c#.nettask-parallel-libraryasync-await

Task(async, await): Do I need to enter these are all connecting layers or only ones with async calls i.e HttpClient.GetAsync?


I have come across a small issue. I have written a asp.net web api service and I automatically added "async" on the controller, of course this now requires that I use await.

The problem I have is that my controller is connected to a service layer and this service layer then connects to a data layer - this data layer is the layer that is calling an ASYNC version of GET to make an asynchronous call to another REST service - so this is easy, I can convert my data layer method to have an "async" keyword and i will place a await on the HttpClient GetSync call.

But my service layer to support async / await I need to change the return type to Task<T> but the service layer really isn't doing anything async, it's calling to the data layer that is actually calling HttpClient async methods.

So I have two options considering I have the following layer structure.

ASP.NET Web Api >> Service Layer >> Data Layer

Only have async and await used in the Data Layer and be done with it.

Or place async and await on the controller and the method from the service layer, this requires refactoring as I need to return Task<T>.

I suppose where I am not understanding it fully, technically the only blocking calls would be in the data layer, so to have all threads returned the thread pool for use I should only be concerned with placing async and await on the data layer?

When would I need to use pattern on the controllers?


Solution

  • I automatically added "async" on the controller, of course this now requires that I use await.

    That is backwards. You should only add async to a method if you need to use await.

    Only have async and await used in the Data Layer and be done with it.

    You shouldn't wrap asynchronous methods within synchronous APIs. This is especially true in server code, because then you lose all the benefits of async.

    Or place async and await on the controller and the method from the service layer, this requires refactoring as I need to return Task.

    This is the correct approach. Follow these guidelines:

    1. Do not block on async code. E.g., do not call Task.Wait or Task<T>.Result. I describe on my blog how this can cause deadlocks, but even if you hack it to work reliably, you'll still lose all the benefits of async on the server side.
    2. Avoid async void. Especially on the server side.
    3. Instead of Wait or Result, use await. This means that the awaiting method will have to be async Task or async Task<T>, which means that methods that call the awaiting method will also have to await. So async will "grow" through your code. This is normal and correct.

    You may find my article on Best Practices in Asynchronous Programming helpful.