I’ve had an issue a bit like this occasionally with Task.Run()/Task.Factory.StartNew(), so I think there must be something very basic I’m not understanding about its use (for those who like curly braces, my apologies for having to muddle through VB):
I have an async method with the following code:
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
It is called from a synchronous method like so:
Dim result = ModelService.MeterResolution.SaveMeter(data).Result
From what I understood this should wait until the method SaveMeter() returns with a result. And the async method I laid out previously should wait on the Task.Run line until it returns, and then continues (hence the await). Instead, what happens is that as soon as the Await line is hit, the callstack seems to exit. The SaveChanges() succeeds, but I’m unable to inform the client of this fact.
I use the TPL relatively frequently in a different application and haven’t had these issues, but there’s no method like context.SaveChanges() I need to use.
Any suggestions are appreciated. I hope i’m not just mis-reading the documentation.
The problem is actually due to your use of
Result. Callingasynccode from synchronous code can be quite tricky.I explain the full reasons for this deadlock on my blog. In short, there’s a “context” that is saved by default at the beginning of each
awaitand used to resume the method.So if this is called in a UI or ASP.NET context, when the
awaitcompletes, theasyncmethod tries to re-enter that context to continue executing. Unfortunately, code usingResult(orWait) will block a thread in that context, so theasyncmethod cannot complete.The guidelines to avoid this are:
ConfigureAwait(continueOnCapturedContext: false)as much as possible. This enables yourasyncmethods to continue executing without having to re-enter the context.asyncall the way. Useawaitinstead ofResultorWait.