Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using async/await or task in web api controller (.net core)

I have a .net core API which has a controller that builds an aggregated object to return. the object it creates is made of data that comes from 3 method calls to a service class. These are all independent of each other and can be run in isolation from each other. Currently I am using tasks to improve the performance of this controller. the current version looks something like this...

[HttpGet] public IActionResult myControllerAction() {           var data1 = new sometype1();     var data2 = new sometype2();     var data3 = new List<sometype3>();      var t1 = new Task(() => { data1 = service.getdata1(); });     t1.Start();      var t2 = new Task(() => { data2 = service.getdata2(); });     t2.Start();      var t3 = new Task(() => { data3 = service.getdata2(); });     t3.Start();      Task.WaitAll(t1, t2, t3);      var data = new returnObject     {          d1 = data1,          d2 = data2,          d2 = data3     };      return Ok(data); } 

This works well however I am wondering if using tasks is the best solution here? Would using async/await be a better idea and more accepted way?

For example should the controller be marked as async and an await put on each call to the the service methods?

like image 358
Ben Cameron Avatar asked Jan 31 '17 08:01

Ben Cameron


People also ask

Should I use async in Web API?

In general, you should make a method asynchronous if the synchronous method blocks the ASP.NET request thread while doing no work. By making the call asynchronous, the ASP.NET request thread is not blocked doing no work while it waits for the web service request to complete.

Should I use async controller actions?

async actions help best when the actions does some I\O operations to DB or some network bound calls where the thread that processes the request will be stalled before it gets answer from the DB or network bound call which you just invoked.

Why we use async and await in Web API?

The async/await feature solves three performance or scalability problems: They can make your application handle more users. If you have requests that access an external resource such as a database or a web API then async frees up the thread while it is waiting.

What is use of async and await in .NET core?

The async and await keywordsAn asynchronous method is one that is marked with the async keyword in the method signature. It can contain one or more await statements. It should be noted that await is a unary operator — the operand to await is the name of the method that needs to be awaited.

What is async and await in ASP NET Core?

All of these leads to improved scalability of our application. These two keywords – async and await – play a key role in asynchronous programming in ASP.NET Core. We use the async keyword in the method declaration and its purpose is to enable the await keyword within that method.

How to await for tasks with async method in Java?

Thus with async method you can await for tasks instead of blocking thread. Instead of creating local variables and assigning them in tasks, you can use Task<T> to return results of required type.

What is the use of await keyword in ASP NET Core?

These two keywords – async and await – play a key role in asynchronous programming in ASP.NET Core. We use the async keyword in the method declaration and its purpose is to enable the await keyword within that method. So yes, you can’t use the await keyword without previously adding the async keyword in the method declaration.

Should the controller be marked as async and await?

For example should the controller be marked as async and an await put on each call to the the service methods? Show activity on this post. This works well however I am wondering if using tasks is the best solution here? Would using async/await be a better idea and more accepted way? Yes, absolutely.


2 Answers

This works well however I am wondering if using tasks is the best solution here? Would using async/await be a better idea and more accepted way?

Yes, absolutely. Doing parallel processing on ASP.NET consumes multiple threads per request, which can severely impact your scalability. Asynchronous processing is far superior for I/O.

To use async, first start with your lowest-level call, somewhere inside your service. It's probably doing an HTTP call at some point; change that to use asynchronous HTTP calls (e.g., HttpClient). Then let async grow naturally from there.

Eventually, you'll end up with asynchronous getdata1Async, getdata2Async, and getdata3Async methods, which can be consumed concurrently as such:

[HttpGet] public async Task<IActionResult> myControllerAction() {   var t1 = service.getdata1Async();   var t2 = service.getdata2Async();   var t3 = service.getdata3Async();   await Task.WhenAll(t1, t2, t3);    var data = new returnObject   {     d1 = await t1,     d2 = await t2,     d3 = await t3   };    return Ok(data); } 

With this approach, while the three service calls are in progress, myControllerAction uses zero threads instead of four.

like image 107
Stephen Cleary Avatar answered Sep 24 '22 16:09

Stephen Cleary


[HttpGet] public async Task<IActionResult> GetAsync() {           var t1 = Task.Run(() => service.getdata1());     var t2 = Task.Run(() => service.getdata2());     var t3 = Task.Run(() => service.getdata3());      await Task.WhenAll(t1, t2, t3);      var data = new returnObject     {         d1 = t1.Status == TaskStatus.RanToCompletion ? t1.Result : null,         d2 = t2.Status == TaskStatus.RanToCompletion ? t2.Result : null,         d3 = t3.Status == TaskStatus.RanToCompletion ? t3.Result : null     };     return Ok(data); } 
  1. Your action thread is currently blocked when you are waiting for tasks. Use TaskWhenAll to return awaitable Task object. Thus with async method you can await for tasks instead of blocking thread.
  2. Instead of creating local variables and assigning them in tasks, you can use Task<T> to return results of required type.
  3. Instead of creating and running tasks, use Task<TResult>.Run method
  4. I recommend to use convention for action names - if action accepts GET request, it's name should starts with Get
  5. Next, you should check whether tasks completed successfully. It is done by checking task status. In my sample I used null values for return object properties if some of tasks do not complete successfully. You can use another approach - e.g. return error if some of tasks failed.
like image 30
Sergey Berezovskiy Avatar answered Sep 22 '22 16:09

Sergey Berezovskiy