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

南楼画角 提交于 2019-12-17 14:47:54

问题


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?

回答1:


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.




回答2:


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.



来源:https://stackoverflow.com/questions/26205173/using-async-keyword-in-method-signature-to-return-a-task-in-web-api-endpoint

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!