Wednesday, December 19, 2012

Using async/await (TPL) with Orchard

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.

A short list of C# coding issues.

Injecting services into entities It been bugging me for a while now that to use services in a entity can be a bit of pain. It usually starts...