While working on a module for Orchard CMS I ran into some problems trying to glue async (Task) based code with (classic) synchronous code.
Here's the set-up:- Service TheMovieDb to call themovedb.org api.
- Service MovieInfo service to integrate TheMovieDb with Orchard.
- AdminController for front-end to call MovieInfo and coordinate views.
TheMoveDb uses Tasks, so I don't have to wait around for across-the-wire calls. MovieInfo uses Tasks, and integrates with orchard services. AdminController uses normal Action methods.
Being a TDD developer, all the pieces looked fine. But as soon as I put it together... splat.
It all starts with a deadlock (doesn't it always!). A quick google gets to Stephen Cleary (via SO) Don't Block on Async Code and Async and Await Armed with this I now at-least understand the problem.
Alas, at least in Orchard 1.6, async controllers are a no-go. It took a fair bit of searching, I finally found an SO article describing the problem. So (for now) I've settled on a sync / async solution.
Putting it all together:- TheMoveDb service stays as a normal async service.
- MovieInfo service calls TheMoveDb with ConfigureAwait(false).
- AdminController stay synchronous; blocks on calls to MovieInfo, waiting for Result.
There was one last gotcha; anything after the await in MovieInfo service executes on its own thread. So no access to orchard services (such as WorkContext etc). To get around this I just had to take care to no need the 'orchard friendly' thread context after the await.
No comments:
Post a Comment