Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using async keyword in method signature to return a Task in Web Api endpoint

If I wanted to write a non-blocking web api action by returning a Task object, I could do it with or without using the async keyword as such:

Using async

public async Task<HttpResponseMessage> Get()
{
    Func<HttpResponseMessage> slowCall = () =>
    {
        Thread.Sleep(2000);
        return Request.CreateResponse(HttpStatusCode.OK, "Hello world");
    };

    var task = Task<HttpResponseMessage>.Factory.StartNew(slowCall);
    return await task;
}

Without using async

public Task<HttpResponseMessage> Get()
{
    Func<HttpResponseMessage> slowCall = () =>
    {
        Thread.Sleep(2000);
        return Request.CreateResponse(HttpStatusCode.OK, "Hello world");
    };

    var task = Task<HttpResponseMessage>.Factory.StartNew(slowCall);
    return task;
}

They both work properly. However, every example I've seen (online and in books) on writing a web api action that returns a Task uses the async keyword. Granted, I understand that gives you more flexibility as it allows you to control what you want to "await" on and what not. But assuming your functionality could be effectively handled either way,

  • Is there any advantage to using one approach vs the other?
  • Should I always use the async keyword (and if so why)?
  • Or is it irrelevant?
like image 976
rtorres Avatar asked Oct 05 '14 17:10

rtorres


People also ask

Is an async method that returns Task?

Async methods can have the following return types: Task, for an async method that performs an operation but returns no value. Task<TResult>, for an async method that returns a value. void , for an event handler.

What is async Task in Web API?

In the context of Web API, Asynchronous programming is used to improve the scalability of the application. By applying asynchronous programming using async and await there won't be any direct performance gain in speed instead application will be able to handle more concurrent requests.

What does the async keyword in a method signify?

The async keyword turns a method into an async method, which allows you to use the await keyword in its body. When the await keyword is applied, it suspends the calling method and yields control back to its caller until the awaited task is complete. await can only be used inside an async method.

Which of the following keyword does async method uses to label suspension point?

The marked async method can use await to designate suspension points.


2 Answers

The async keyword allows you to use an await in your method by creating a state machine. If you can manage returning an asynchronous task without using it you can go ahead and remove it because it has some (very small) overhead. Keep in mind though that it's only useful in a few cases. Your return await is one of them.

Another difference is how exceptions are handled. If there's an exception in the synchronous part of the method and it's marked as async the exception will be stored in the returned task. Without the keyword the exception would be thrown regularly. For example in this case there's a big difference:

var task = Get(); // unhandled exception without async
try
{
    var result = await task; // handled exception with async
}
catch
{
}

My recommendation is to use the async keyword even when you don't absolutely need to*, because most developers don't understand the difference and the value in the optimization is mostly negligible.


* Unless you and your teammates really know what you're doing.

like image 145
i3arnon Avatar answered Oct 17 '22 02:10

i3arnon


There is one advantage to bypassing the await and returning the Task directly: performance. You won't allocate or process the state machine that goes with an async method. There are, however, some subtle differences when exceptions are involved.

In the async example, any exceptions thrown will be enclosed in a Task. This is generally what people assume will happen when they call a Task-returning method. In the sync example, exceptions will be thrown immediately upon invocation.

This will also have an effect on the exception's stack trace. In the async example, it will show Get(). In the sync example, it will show your anonymous delegate or worse, some internal crap in Task.Factory.StartNew with no actual reference to your actual code. This can result in being a little more difficult to debug.

like image 22
Cory Nelson Avatar answered Oct 17 '22 02:10

Cory Nelson