异步控制器方法没有返回

时间:2014-07-30 11:32:06

标签: c# asp.net asp.net-web-api async-await

当我向它发出请求时,此代码会挂起(不会返回响应):

public class MyController : ApiController
{
    public async Task<IQueryable<int>> Get()
    {
        return await new Task<IQueryable<int>>(() => new List<int>().AsQueryable());
    }
}

但这种方法很好用:

public IQueryable<int> Get()
{
    return new List<int>().AsQueryable();
}

我错过了什么基础知识?!

3 个答案:

答案 0 :(得分:6)

正如另一个答案所指出的,控制器未完成的原因是因为任务未启动。但是,使用Task.StartTask.Factory.StartNewTask.Run并不是ASP.NET的好方法。

在ASP.NET上使用async / await的全部意义是释放一个帖子。但是,如果您await通过Start / StartNew / Run启动了一项任务,那么您可以通过占用另一个线程来释放一个线程来自同一线程池的线程。在这种情况下,您不仅会失去async / await的所有好处,而且通过定期抛弃ASP.NET线程池启发式实际上降低您的可伸缩性。< / p>

正如我在我的博客中描述的那样two types of tasks:代表任务(代表在线程上执行的一些工作)和Promise Tasks(代表一个事件)。您应该避免在ASP.NET上委派任务,包括任何已启动的任务&#34; (Start / StartNew / Run)。

由于您正在返回IQueryable<T>,我假设您的实际基础操作是数据库查询。如果您正在使用EF6,那么您完全支持使用Promise Tasks正确实施的asynchronous queries

答案 1 :(得分:3)

你实际上并没有开始Task所以它会等待永远不会开始的事情。

而是使用Task.Factory.StartNew来创建并同时启动,或者调用Task#Start并等待该调用。

开始任务的方法概述:http://dotnetcodr.com/2014/01/01/5-ways-to-start-a-task-in-net-c/

答案 2 :(得分:0)

async / await中完全没有必要,该方法可能如下所示:

public Task<IQueryable<int>> Get()
{
    return Task.FromResult(new List<int>().AsQueryable());
}

如果你确实需要它async,那么你总是可以这样写:

public async Task<IQueryable<int>> Get()
{
    return await Task.FromResult(new List<int>().AsQueryable());
}

这将引入很少的开销(整个状态机将由编译器生成)。

另外,正如其他人已经说过的那样,从async方法返回的任务应(已启动)

请注意,Task.FromResult将返回已完成的任务,此案例可以通过async/await生成的代码进行优化,在这种情况下编写Task.Run至少是非常奇怪的

阅读Task-based Asynchronous Pattern了解更多详情