避免使用Async重复代码

时间:2014-05-29 12:03:05

标签: c# .net asp.net-mvc async-await

如何避免为异步和非异步方法编写两次相同的代码。 我目前正在使用ASP.NET,所以我目前正在使用请求线程,我很快就知道他在代码下面(应该显示我的意图),这肯定是错误的做法。

应用程序死锁,因为await关键字试图返回.Result阻塞的同一个线程。

我这样做的全部原因是避免写相同的" FindAll"代码两次。

public IEnumerable<Resource> FindAll()
{
   return FindAllAsync().Result;

}

public async Task<IEnumerable<Resource>> FindAllAsync()
{
   return await Context.Resources.ToListAsync();
}

那你怎么解决这个问题呢?

2 个答案:

答案 0 :(得分:11)

  

如何避免为异步和非异步方法编写相同的代码两次。

在一般情况下,你不可以。

有问题的操作要么是自然异步的,要么是自然同步的。在此示例(数据库请求)中,它自然是异步的。因此,使API异步。就是这样。

Stephen Toub有一对着名的博客文章Should I expose synchronous wrappers for asynchronous methods?Should I expose asynchronous wrappers for synchronous methods?这两个问题的简短答案是&#34;没有。&#34;

你可以做各种黑客来揭露这两种类型的API(斯蒂芬在他的帖子中涵盖了每种方法),但与缺点相比,其好处是微不足道的。

答案 1 :(得分:3)

同步和异步方法应采取不同的行动。通常这意味着同步调用应该调用作为请求的一部分阻塞的API,async应该调用“一直异步”的API

如果您不想创建完全同步的api,在您的情况下,您可以使用ConfigureAwait(false)

当您使用Task标记ConfigureAwait(false)时,您实际上说的是“不需要在同一{{await内运行延续(SynchronizationContext之后的代码) 1}},你可以在你当前的上下文中完成(通常是一个ThreadPool线程)“

至于第二种方法,您可以删除async关键字并保存状态机的冗余生成:

public IEnumerable<Resource> FindAll()
{
     return FindAllAsync().Result;
}

public Task<IEnumerable<Resource>> FindAllAsync()
{
     return Context.Resources.ToListAsync();
}

一些阅读参考:

Stephan Cleary - Dont block on async code

Best practice to call ConfigureAwait(false)

Task.ConfigureAwait(false) MSDN