Silverlight: MVVM Service Agent with Exceptionhandling

Tags: silverlight, ria, serviceAgent, webservice, pattern, download, ef, entityFramework

In this small code snippet let us intrduce a pattern that you may use in a MVVM (Model-View-View-Model) class to encapsulate RIA-Service functionality from your MVVM-Class. This makes it testable and you can catch  errors that ocures when accessing the Webservice.
What you get:

  • The MVVM has no dependency to the ObjectContext
  • Catch Exeptions that may occur when talking to the WCF-Service

Why do you need it?
Normally when debugging your Silverlight-RIA-Application you may implement your MVVM-Class like this:

using Catel.MVVM;
using System;
using System.Linq;
using X4U.Fahrdienstplaner.Services;
using System.Collections.ObjectModel;
using X4U.Fahrdienstplaner.Web.Models;
using Catel.Data;
using System.Collections.Generic;
using System.Windows;
using X4U.Fahrdienstplaner.Web.Services;
using System.ServiceModel.DomainServices.Client;
 
/// <summary>
/// UserControl view model.
/// </summary>
public class MapsViewModel : ViewModelBase {
 
    /// <summary>
    /// The Datacontext / Proxy to the WCF-Service
    /// </summary>
    MapsContext _Context = new MapsContext();
 
    /// <summary>
    /// Initializes a new instance of the <see cref="MapsViewModel"/> class.
    /// </summary>
    public MapsViewModel() {
        LoadOperation<Vehicle> loadOperation = _Context.Load(_Context.GetVehicleSetQuery(_clientId),  GetAllVehiclesCallBack, false);
    }
 
    private void GetAllVehiclesCallBack(LoadOperation<Vehicle> loadOperation) {
        if (loadOperation.HasError) {
            MessageBox.Show(string.Format("Retrieving data failed: {0}", loadOperation.Error.Message));
            loadOperation.MarkErrorAsHandled();
        } else {
            Vehicles = new ObservableCollection<Vehicle>(loadOperation.Entities);
        }
    }
   
    /// <summary>
    /// Gets or sets the property value.
    /// </summary>
    public ObservableCollection<Vehicle> Vehicles {
        get { return GetValue<ObservableCollection<Vehicle>>(VehiclesProperty); }
        set { SetValue(VehiclesProperty, value); }
    }
 
    /// <summary>
    /// Register the  Vehicles property so it is known in the class.
    /// </summary>
    public static readonly PropertyData VehiclesProperty = RegisterProperty("Vehicles", typeof(ObservableCollection<Vehicle>));
 
}

When using the Service Agent Pattern introduced in this Article:
http://www.silverlight.net/learn/advanced-techniques/the-mvvm-pattern/using-the-mvvm-pattern-in-silverlight-applications

you get no correct Errorhandling.
So we slightly enhanced this Pattern and what comes out is this nice Service Agent Class:

using System;
using System.Collections.ObjectModel;
using X4U.Fahrdienstplaner.Web.Models;
using X4U.Fahrdienstplaner.Web.Services;
 
namespace X4U.Fahrdienstplaner.Services {
    public class MapsServiceAgent {
 
        MapsContext _Context = new MapsContext();
        int _clientId = 1;
 
        public void GetAllVehicles(Action<ObservableCollection<Vehicle>, Exception> callback) {
            Exception ex = null;
            var entities = new ObservableCollection<Vehicle>();
            _Context.Load(_Context.GetVehicleSetQuery(_clientId), (lo) => {
                if (lo.HasError) {
                    ex = lo.Error;
                    lo.MarkErrorAsHandled();
                } else {
                    entities = new ObservableCollection<Vehicle>(lo.Entities);
                }
                callback.Invoke(entities, ex);
            }, null);
        }
    }
}

The usage is easy, you just pass in the Callback-Method that should be called when the Operation has been finnished.
Below you can see the modified MVVM-Implementation.

/// <summary>
/// UserControl view model.
/// </summary>
public class MapsViewModel : ViewModelBase {
 
    /// <summary>
    /// The Service Agent Class
    /// </summary>
    MapsServiceAgent _mapsServiceAgent = new MapsServiceAgent();
 
    /// <summary>
    /// Initializes a new instance of the <see cref="MapsViewModel"/> class.
    /// </summary>
    public MapsViewModel() {
        _mapsServiceAgent.GetAllVehicles(GetAllVehiclesCallBack);
    }
 
    private void GetAllVehiclesCallBack(ObservableCollection<Vehicle> entities, Exception ex) {
        if (ex!=null) {
            MessageBox.Show(string.Format("Retrieving data failed: {0}", ex.Message));
        } 
        Vehicles = entities;
    }
   
    /// <summary>
    /// Gets or sets the property value.
    /// </summary>
    public ObservableCollection<Vehicle> Vehicles {
        get { return GetValue<ObservableCollection<Vehicle>>(VehiclesProperty); }
        set { SetValue(VehiclesProperty, value); }
    }
 
    /// <summary>
    /// Register the  Vehicles property so it is known in the class.
    /// </summary>
    public static readonly PropertyData VehiclesProperty = RegisterProperty("Vehicles", typeof(ObservableCollection<Vehicle>));
 
}

That’s all folks!

Happy coding,

X4U Team

Add a Comment