
Silverlight: MVVM Service Agent with Exceptionhandling
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