Recently, I tried to use an async action on an MVC controller in Sitefinity and was greeted with the error message:
"The asynchronous action method 'IndexAsync' returns a Task, which cannot be executed synchronously."
This was in Sitefinity 8.0. Async actions have been supported in MVC since MVC 4.0 (which is the version leveraged by Sitefinity 8.0). See Using Asynchronous Methods in ASP.NET MVC 4 for more information regarding this.
Does Sitefinity support async MVC actions? / Am I missing a setting allowing this?
If not, when will Sitefinity support this?
For reference, I am using the following temporary workaround right now:
async Task<ActionResult> IndexAsync()...
I'd like to know this as well.
The async creep is only going to expand further in my project as we're using an external ASP.NET Identity based solution which heavily uses the Task-based Asynchronous Pattern. Aside from that, we're using HttpClient for server-to-server web requests to communicate between various 3rd-party systems.
And I'd really like to not have to wrap every controller action with a synchronous, blocking version relying on .Result ...
sender, EventArgs e)
sender, ExecutedEventArgs e)
, action =
, id = (
so given that this is still a limitation, what strategies are people using to work around it?
We have a site that is needing to make async (HttpClient) calls to an external service to load content into various Sitefinity widgets...
The way I see it we have three options:
1 - Use Webclient to make all Http calls synchronously. This seems the most straightforward, but I don't know what kind of impact it would have on performance if several hundred people are using the same page at once...
2 - Use classic MVC and handle these requests outside of the Sitefinity context. This gives us full control, but we lose all the layout and templating (not to mention other SF widgets like navigation, etc.) from sitefinity, so it's probably a last resort type option.
3 - Implement these pages using client-side requests, either via AJAX or a SPA with something like angular. I like this idea, but I don't know how you well SPA apps work on a Sitefinity page, has anybody done something like this?
Are there any other strategies for being able to work with Sitefinity MVC Feather widgets that have async tasks in their actions?
@SelAromDotNet : You posted this in May - sorry for the late reply, I just saw this.
First, read this excellent blog post by Stephen Cleary titled "There is no Thread" - it explains that when an async method awaits a method that performs an async I/O operation, there is no thread handling the wait. In your controller action, when the thread that is processing your request within the IIS request pipeline comes to the instructions to await an async web request, it signals the machine's NIC device driver to make a request to the external service, and then the thread is released to handle processing other requests in IIS. When the request to the external service completes, the NIC driver signals (via a bunch of low level events) that the request has completed, and IIS assigns a thread pool thread to the continuation to finish the processing of your controller's action method. This means that the entire time the HTTP request to the external service is pending, the thread that was initially processing your request is free to perform other work.
So the options that you've laid out:
1) Use WebClient to make "synchronous" HTTP requests - This is effectively the same thing as blocking on an async HttpClient request. In both instances the underlying request is being performed asynchronously by the device driver, but the .NET code issuing that request is blocking the thread while waiting for a response. This means that thread is tied up, doing nothing, until the request to the external service completes.
This is what the work around I posted in the initial post is doing. Note that either of these methods synchronously execute async code, and both block the thread while doing so:
// Or this does the same thing, but thrown exceptions don't get wrapped in an AggregateException...
Task.Run(() => IndexAsync())
This work around, blocking on async code, can cause the execution of your request's processing to deadlock. See Don't Block on Async Code
For information about .Result vs. Task.Run(...).GetAwaiter().GetResult() see A Tour of Task, Part 6: Results
2) You could use classic MVC, but then why are you even using Sitefinity?
3) This is probably your best bet, you get to keep Sitefinity's widget functionality and you aren't blocking while synchronously executing async code. If this is possible, by all means, go for it.
Are there any other strategies for handling async actions in SF? Nope, those three are the three options you have: 1) use SF and execute async methods synchronously, blocking the thread handling the request; 2) use Classic mode which bypasses Sitefinity's routing and view engine - essentially a non-SF application with the SF backend available via the SF APIs; 3) use SF, but only non-async actions, and make AJAX requests to services hosted outside of SF that properly use async actions.
Unfortunately, none of those solve the problem of proper handling of async actions on controllers in Sitefinity. They're all just ways to work around the problem.