使用dbContext.savechanges()等待任务'迷路'

时间:2013-01-23 01:23:21

标签: .net vb.net entity-framework task-parallel-library

我偶尔会遇到一个类似于Task.Run()/ Task.Factory.StartNew()的问题,所以我认为必须有一些非常基本的东西,我不了解它的用法(对于那些就像花括号一样,我为不得不混淆VB而道歉:

我有一个使用以下代码的异步方法:

       Try
        Using context As New ECOSSContext


            context.Meters.Attach(entity)


            Await Task.Run(Sub() _
                               context.SaveChanges() _
                               )

            'ANY CODE HERE NEVER GETS FIRED


        End Using

        Return True

    Catch ex As Exception
        Return False
    End Try

从同步方法调用它:

Dim result = ModelService.MeterResolution.SaveMeter(data).Result

理解开始,这应该等到SaveMeter()方法返回结果。我之前列出的异步方法应该等待Task.Run行,直到它返回,然后继续(因此等待)。相反,会发生的是,一旦Await线被击中,callstack似乎就会退出。 SaveChanges()成功,但我无法告知客户这个事实。

我在不同的应用程序中相对频繁地使用TPL并且没有遇到这些问题,但是我没有像context.SaveChanges()那样的方法。

任何建议都表示赞赏。我希望我不只是误读了文档。

1 个答案:

答案 0 :(得分:3)

问题实际上是由于您使用了Result。从同步代码调用async代码可能非常棘手。

我解释full reasons for this deadlock on my blog。简而言之,默认情况下会在每个await的开头保存一个“上下文”,用于恢复该方法。

因此,如果在UI或ASP.NET上下文中调用它,则await完成时,async方法会尝试重新进入该上下文以继续执行。不幸的是,使用Result(或Wait)的代码将阻止该上下文中的线程,因此async方法无法完成。

避免这种情况的指导原则是:

  1. 尽可能使用ConfigureAwait(continueOnCapturedContext: false)。这使您的async方法可以继续执行,而无需重新输入上下文。
  2. 一直使用async。使用await代替ResultWait