Matthew Cox Team : Web Development Tags : Technology Web Development Performance

Async controller actions in Umbraco

Matthew Cox Team : Web Development Tags : Technology Web Development Performance

Following on from my previous blog about thread exhaustion, I recently had to deal with a site experiencing thread exhaustion that happened to be an Umbraco site. This issue was nothing to do with Umbraco itself, it was synchronously calling a fairly slow webservice that was responsible. My solution? Async controllers. As this point I could detail how I created a custom controller factory that would allow me to override the render action invoker to allow asynchronous invocation, but the good news is you don’t need to know any of that. As of Umbraco 6.2.2 and 7.1.5 they have already done that for you. The default render action invoker now inherits from Microsoft’s AsyncControllerActionInvoker, which supports both synchronous and asynchronous invocation.

Now the bad news. Thanks to the fact that Umbraco by default still runs as a .net 4.0 application and not a .net 4.5 application, we have a small issue that makes async controllers borderline unusable. When the application resumes an async call the httpContext is not restored, which ends up causing the Umbraco context to no longer be available. I’m sure in a lot of applications this could be overcome by simply loading everything needed from the Umbraco context before calling any async methods, however in my application this would have required a complete restructure.

So why in an MVC 5 application can you make an async controller that maintains its httpContext throughout the request lifecycle, but not in Umbraco? It’s all to do with the SynchronizationContext. Along with the invention of await/async keywords in .net 4.5 Microsoft also refactored the SynchronizationContext in order to support their usage in asp.net. Microsoft refactored the old AspNetSynchronizationContext into the LegacyAspNetSynchronizationContext and created a new AspNetSynchronizationContext that would support the new task based asynchronous pattern of await/async keywords.

By default when an application is compiled with .net 4.0 the synchronization context used will be the LegacyAspNetSynchronizationContext in order to maintain backwards compatibility with older asynchronous patterns. However you are able to force it to use the new AspNetSynchronizationContext by simply adding the following key to the appSettings of your web.config

<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />

This forces .net to use the correct synchronisation context for your Umbraco application, and will fix the issue of the httpContext not being restored when an async method resumes. Your other option of course is just to make sure that in the compilation section of your web.config, you set the targetFramework to .net 4.5. I’ve just stuck with changing the synchronisation context on the assumption that the Umbraco core devs know what they are doing and have a good reason why they are introducing .net 4.5 concepts (await/async) in a .net 4.0 project.