Thursday, May 10, 2012

One pattern for error handling in MvvmCross


One pattern for how to handle errors/exceptions during async calls in MvvmCross is available in the BestSellers example: MvvmCross BestSellers Sample
BestSellers uses 2 techniques that I find I've used quite a lot in MvvmCross applications:
  • the use of BaseViewModel classes for shared ViewModel code like error handling
  • the use of an app level "error router" to get errors from the ViewModels to UI notifications like UIAlertViews, Toasts and/or MessageBoxes.

At a more detailed level, what BestSellers does is:
Each ViewModel uses a direct call to a webservice for book information. For example the Category List is constructed as:
    public CategoryListViewModel()
    {
        AsyncLoad();
    }

    private void AsyncLoad()
    {
        GeneralAsyncLoad(URL_CATEGORIES, ProcessResult);
    }
where GeneralAsyncLoad is defined in a shared BaseViewModel:
    protected void GeneralAsyncLoad(string url, Action responseStreamHandler)
    {
        try
        {
            IsLoading = true;
            var request = WebRequest.Create(url);
            request.BeginGetResponse((result) => GeneralProcessResponse(request, result, responseStreamHandler), null);
        }
        catch (ThreadAbortException)
        {
            throw;
        }
        // obviously we could do better than catching all `Exception` here!
        catch (Exception exception)
        {
            IsLoading = false;
            ReportError("Sorry - problem seen " + exception.Message);
        }
    }
The ReportError method within the above exception handler uses an injected object - anIErrorReporter.
This injected object is initialised as a singleton during App construction - seeErrorApplicationObject in App.cs
During their construction and setup, the UI projects all subscribe to events from that same singleton - but using an IErrorSource interface instead or IErrorReporter.
This then allows each platform to display it's own error display - e.g.:

Obviously, if you need error handling as well as error displaying - e.g. if you want to retry the asynchronous operation or if you want to load an offline copy of data instead - then you can add this to your error handling within the ViewModel and the BaseViewModel.

8 comments:

  1. Stuart,
    How does this process work in v3? I've tried adding this concept into my v3 app but I think the framework has changed to the point where this approach doesn't work any more.
    I will implement my own error reporting using a messagenger approach but would like to use this "common" approach if it is still available.
    Cheers,

    Steve

    ReplyDelete
    Replies
    1. Afaik this approach should still work... However, I too now generally use the MvxMessenger plugin for distributing the error messages now instead of using the IErrorSource interface. (The MvxMessenger has a SubscribeOnMainThread method which helps for the UI code)

      Delete
    2. Cool, I'll continue on down this road then :)

      Delete
    3. In case you're wondering... any comment on a post older than 3 months gets moderated... sorry, it just helps to keep the spam down... :)

      Delete
  2. Yes, I noticed that :) No worries.....

    ReplyDelete
  3. Ok, so where in the View do I subscribe to messages, I tried this code which doesn't get executed:
    public HomeView(IMvxMessenger messenger)
    {
    _messenger = messenger;

    // Subscribe to inter-app message "ApplicationError_Message"
    _messageToken =
    messenger.SubscribeOnMainThread(Display_Error);
    }

    Steve

    ReplyDelete
    Replies
    1. Please take this to StackOverflow - easier to write and format better questions and answers there.

      Delete
    2. http://stackoverflow.com/questions/16696357/subscribing-to-mvxmessage-from-android-client

      Delete