More in this section

Forums / General Discussions / Does Sitefinity support async MVC actions?

Does Sitefinity support async MVC actions?

10 posts, 1 answered
  1. RJ Cuthbertson
    RJ Cuthbertson avatar
    41 posts
    Registered:
    01 Jun 2015
    27 Jul 2015
    Link to this post

    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?

     

    Thank you,

    RJ Cuthbertson

     

    For reference, I am using the following temporary workaround right now:

    [AcceptVerbs(HttpVerbs.Get)]
    public ActionResult Index()
    {
        return IndexAsync().Result;
    }
     
    [NonAction]
    private async Task<ActionResult> IndexAsync()...

    Answered
  2. Simon
    Simon avatar
    3 posts
    Registered:
    31 Jul 2014
    30 Jul 2015
    Link to this post

    Hey Telerik,

     I'd like to know this as well. 

  3. RJ Cuthbertson
    RJ Cuthbertson avatar
    41 posts
    Registered:
    01 Jun 2015
    30 Jul 2015
    Link to this post

    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 ...

  4. Nikola Zagorchev
    Nikola Zagorchev avatar
    424 posts
    Registered:
    19 Apr 2017
    30 Jul 2015
    Link to this post
    Hello,

    Using the controller in classic MVC will allow you to use async Actions. You can register your own route in Sitefinity 8.1 the following way:
    protected void Application_Start(object sender, EventArgs e)
            {
                Bootstrapper.Initialized += new EventHandler<ExecutedEventArgs>(Bootstrapper_Initialized);
            }
      
            protected void Bootstrapper_Initialized(object sender, ExecutedEventArgs e)
            {
                if (e.CommandName == "RegisterRoutes")
                {
                    RouteTable.Routes.MapRoute(
                        "Classic",
                        "customprefix/{controller}/{action}/{id}",
                        new { controller = "MyController", action = "Index", id = (string)null }
                    );
                }
            }

    This way you can use the async controller actions freely. They will be handled as in a normal web application.
    However, if you use the async Action in a widget, you will indeed get the InvalidOperationException. Currently, we do not support rendering and using MVC Widgets async Actions on both hybrid and pure pages. As you can see from the StackTrace of the error:
    at System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName)
    The ControllerActionInvoker is used rather than the AsyncControllerActionInvoker. You can also observe from the external code while in debugging in VS that the async invoker is called when serving the Action under classic mode when it works correctly.

    Hope this info is useful.

    Regards,
    Nikola Zagorchev
    Telerik
     
    Do you want to have your say in the Sitefinity development roadmap? Do you want to know when a feature you requested is added or when a bug fixed? Explore the Telerik Sitefinity CMS Ideas&Feedback Portal and vote to affect the priority of the items
     
  5. RJ Cuthbertson
    RJ Cuthbertson avatar
    41 posts
    Registered:
    01 Jun 2015
    30 Jul 2015
    Link to this post
    Will asynchronous actions be supported in the future in Hybrid or Pure modes?
  6. Nikola Zagorchev
    Nikola Zagorchev avatar
    424 posts
    Registered:
    19 Apr 2017
    04 Aug 2015
    Link to this post
    Hi,

    Unfortunately, currently this has not been discussed, so it is not in the set plans for the upcoming releases. We are now focused on improving the Feather and providing out of the box functionality for the built in web forms widgets and modules. However, it also depends on the business scenario and desirability of this feature. I have logged a feature request about this in our portal and you can review it on the bellow link:
    http://feedback.telerik.com/Project/153/Feedback/Details/165662-mvc-ability-to-use-async-actions-in-mvc-widgets

    Regards,
    Nikola Zagorchev
    Telerik
     
    Do you want to have your say in the Sitefinity development roadmap? Do you want to know when a feature you requested is added or when a bug fixed? Explore the Telerik Sitefinity CMS Ideas&Feedback Portal and vote to affect the priority of the items
     
  7. RJ Cuthbertson
    RJ Cuthbertson avatar
    41 posts
    Registered:
    01 Jun 2015
    04 Aug 2015 in reply to Nikola Zagorchev
    Link to this post
    Thank you for creating that.
  8. Nikola Zagorchev
    Nikola Zagorchev avatar
    424 posts
    Registered:
    19 Apr 2017
    07 Aug 2015
    Link to this post
    Hi,

    Please, vote for the item and follow its status.
    Thank you all.

    Regards,
    Nikola Zagorchev
    Telerik
     
    Do you want to have your say in the Sitefinity development roadmap? Do you want to know when a feature you requested is added or when a bug fixed? Explore the Telerik Sitefinity CMS Ideas&Feedback Portal and vote to affect the priority of the items
     
  9. SelAromDotNet
    SelAromDotNet avatar
    912 posts
    Registered:
    18 Jul 2012
    09 May
    Link to this post

    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?

    many thanks

  10. RJ Cuthbertson
    RJ Cuthbertson avatar
    41 posts
    Registered:
    01 Jun 2015
    06 Aug in reply to SelAromDotNet
    Link to this post

    @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:

    [AcceptVerbs(HttpVerbs.Get)]
    public ActionResult Index()
    {
       return IndexAsync().Result;

        // Or this does the same thing, but thrown exceptions don't get wrapped in an AggregateException...
       return Task.Run(() => IndexAsync())
          .GetAwaiter()
          .GetResult();
    }
    [NonAction]
    private async Task<ActionResult> 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.

    You do seem to be a bit confused about what a SPA is though. Any way about it, making a web request from the client side will be an AJAX/XHR request. The Single Page Application architecture is just a way to organize your code such that there is only one HTML document requested and served during the entirety of your application's life time. The web browser loads the HTML document once, and then JavaScript is used to make AJAX/XHR requests to load content and dynamically manipulate the DOM thereafter.

    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.

10 posts, 1 answered