CSharpFeeds - All your C# feeds in one place.

Sponsors

Wednesday, December 30, 2009

Magellan Asynchronous Controllers

by Paul Stovell via Paul Stovell on 12/30/2009 5:15:03 AM

Back to: Magellan Home

Magellan 1.1 brings support for asynchronous controllers. First we'll look at what it enables, then I will show some ways to configure it.

The controller action below makes a WCF call to load a list of customers, which are used as the model for the view. This service call could take some time to evaluate:

public class CustomerController : Controller
{
    public ActionResult List()
    {
        Model = CustomerService.GetCustomers();
        return Page("CustomerList");
    }
}

With asynchronous controllers enabled, Magellan will invoke the List action on a background thread. Since page navigation has to take place on the UI thread, the page rendering will be automatically dispatched to the UI thread, but this happens after the controller action has been executed. The result is that the UI remains snappy and responsive.

Enabling Asynchronous Controllers

There are three simple options for enabling asynchronous controllers. The first option is to inherit from AsyncController instead of Controller:

public class CustomerController : AsyncController

The second option is to assign the AsyncActionInvoker when the controller is constructed (this is actually what both AsyncControllerFactory and AsyncController do):

public class CustomerController : Controller
{
    public CustomerController() 
    { 
        ActionInvoker = new AsyncActionInvoker();
    }
}

The preferred approach is to rely on controller factories to set the action invoker. Instead of using CoontrollerFactory, you can use AsyncControllerFactory:

var controllerFactory = new AsyncControllerFactory();
controllerFactory.Register("Home", () => new HomeController());
controllerFactory.Register("Customer", () => new CustomerController());

If you are using a custom controller factory, you just need to replace the ActionInvoker - for example:

public ControllerFactoryResult CreateController(NavigationRequest request, string controllerName)
{
    var controller = // Create controller
    if (controller is ControllerBase)
    {
        ((ControllerBase) controller).ActionInvoker = new AsyncActionInvoker();
    }
    return new ControllerFactoryResult(controller);
}

Reporting Progress

Now that navigation is occurring on a background thread, it's nice to show a progress indicator while navigation is happening. For this, Magellan now provides an INavigationProgressListener interface that you can implement.

public interface INavigationProgressListener
{
    void UpdateProgress(NavigationRequest request, NavigationStage navigationStage);
}

For example, the code behind for the Window is going to show a progress bar:

public partial class MainWindow : Window, INavigationProgressListener
{
    public MainWindow()
    {
        InitializeComponent();
        NavigationProgress.Listeners.Add(this);
        Loaded += (x, y) => Navigator.For(Frame).NavigateWithTransition("Home", "Home", "ZoomIn");
    }

    public void UpdateProgress(NavigationRequest request, NavigationStage navigationStage)
    {
        Dispatcher.Invoke(
            new Action(delegate
            {
                switch (navigationStage)
                {
                    case NavigationStage.BeginRequest:
                        ProgressBar.Visibility = Visibility.Visible;
                        break;
                    case NavigationStage.Complete:
                        ProgressBar.Visibility = Visibility.Collapsed;
                        break;
                }
            }));
    }
}

The iPhone sample application uses a spinning circle to indicate navigation progress:

A spinning indicator is used

The NavigationStage enum provides an indication as to where the request is up to. The table below explains each state:

StepStageDescription
1 BeginRequestThis occurs at the start of the navigation request before the controller has been resolved.
2 ResolvingControllerThis indicates that the controller is about to be resolved by name from the current controller factory.
3 ResolvingActionThis indicates that the controller has been resolved, and the action is now about to be resolved.
4 PreActionFiltersThis indicates that the action has been resolved, and pre-action filters are about to be invoked.
5 ExecutingActionThis indicates that pre-action filters have been invoked, and the action is about to to executed. This event does not always occur (pre-action filters can cancel the navigation request, for example).
6 PostActionFiltersThis indicates that the action has been invoked, and post-action filters are about to to executed. This event does not always occur (pre-action filters can cancel the navigation request, for example).
7 PreResultFiltersThis indicates that the action has been executed and all action filters have been invoked. The result is now about to be evaluated. This event does not always occur (action filters can cancel the navigation request, for example).
8 ExecutingResultThis indicates that the pre-result filters have been executed, and the result is about to be executed (this is typically when views are rendered). This event does not always occur (action filters or pre-action filters can cancel the navigation request, for example).
9 PostResultFiltersThis indicates that the result has been executed (and views have been rendered) and the post-result filters are about to be executed.
10 CompleteThis indicates that the navigation request has been completed (whether successfully or failed), any views have been rendered and any resources from the navigation request have been cleared up.

Summary

The benefit of this approach is that controller code is the same whether we are using single threads or background threads, which also allows unit tests to remain singly threaded while at runtime the application is multi-threaded. Enabling this feature is quite easy, and so long as your controllers don't depend on the UI thread it should Just Work.

Back to: Magellan Home

email it!bookmark it!digg it!

Original Post: Magellan Asynchronous Controllers

Subscribe

New Feed

Product Spotlight

Recently Updated Sources

Legal Note

The content of the postings is owned by the respective author. CSharpFeeds is not responsible for the contents of the postings. This site is automatically generated and cannot be reviewed for abusive content. If you find abusive content on CSharpFeeds, please contact us. Designated trademarks and brands are the property of their respective owners. All rights reserved.

Advertise with us