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:
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;
}
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,
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.
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.
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.
The marked async method can use await to designate suspension points.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With