Introduction
In my previous article, I've shown how to consume a WCF service in a Silverlight application without static proxy generation, by creating its asynchronous twin interface. This article will show how to greatly simplify code which calls WCF services asynchronously. While the solution will be presented in the context of Silverlight applications, you can easily use it in any other code which deals with asynchronous method calls.
Background
Let's first see an example application which I'll be using to present the solution. It's a well-known TODO list application. The main use-cases are:
- List all tasks
- Create new task
- Mark task as completed
- Delete task
The Task
entity:
[DataContract]
public class Task
{
[DataMember]
public Guid Id
{
get; set;
}
[DataMember]
public string Description
{
get; set;
}
[DataMember]
public bool IsCompleted
{
get; set;
}
[DataMember]
public DateTime Created
{
get; set;
}
[DataMember]
public DateTime Completed
{
get; set;
}
}
The TaskService
interface:
[ServiceContract]
public interface ITaskService
{
[OperationContract]
Task[] GetAll();
[OperationContract]
Task Create(string description);
[OperationContract]
Task MarkComplete(Guid id);
[OperationContract]
void Delete(Guid id);
}
And its implementation:
public class TaskService : ITaskService
{
static readonly List<Task> tasks = new List<Task>();
public Task[] GetAll()
{
return tasks.ToArray();
}
public Task Create(string description)
{
var task = new Task
{
Id = Guid.NewGuid(),
Description = description,
Created = DateTime.Now
};
tasks.Add(task);
return task;
}
public Task MarkComplete(Guid id)
{
Task task = tasks.Find(x => x.Id == id);
task.IsCompleted = true;
task.Completed = DateTime.Now;
return task;
}
public void Delete(Guid id)
{
Task existent = tasks.Find(x => x.Id == id);
tasks.Remove(existent);
}
}
The UI is simple, and looks like the one below:
I'm using the MVVM pattern here (which you cannot escape if you're a WPF/Silverlight developer; in case you don't know what MVVM is all about, you can find plenty of articles on the subject here on CP or on the web; I suggest reading Jeremy's article on the subject). The control buttons are bound to the corresponding commands, and the viewable/editable properties are bound to the respective observable properties.
The XAML code for the corresponding view:
<!---->
<UserControl x:Class="Sample.Silverlight.WCF.Views.TaskManagementView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:Utility="clr-namespace:Sample.Silverlight.WCF.Utility"
mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400"
Loaded="UserControl_Loaded">
<UserControl.Resources>
<Utility:BooleanToForegroundConverter x:Key="foregroundConverter"/>
<Utility:BooleanToVisibilityConverter x:Key="visibilityConverter"/>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Width="400" Height="300">
<Grid>
<TextBox Text="{Binding Description, Mode=TwoWay, UpdateSourceTrigger=Explicit}"
TextChanged="DescriptionTextChanged"/>
<Button Content="Create" Command="{Binding CreateCommand}"/>
<ListBox ItemsSource="{Binding Tasks}"
SelectedItem="{Binding Selected, Mode=TwoWay}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding Description}"
Foreground="{Binding IsCompleted, Converter={StaticResource foregroundConverter}}"/>
<Line Stretch="Fill" X2="20"
X1="0" StrokeThickness="1"
Stroke="Black"
Visibility="{Binding IsCompleted, Converter={StaticResource visibilityConverter}}"/>
<ToolTipService.ToolTip>
<ToolTip>
<Grid>
<TextBlock Text="Created: "/>
<TextBlock Text="{Binding Created}"/>
<TextBlock Text="Updated: "/>
<TextBlock Text="{Binding Completed}"/>
</Grid>
</ToolTip>
</ToolTipService.ToolTip>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button Content="Mark Complete" Command="{Binding MarkCompleteCommand}"/>
<Button Content="Delete" Command="{Binding DeleteCommand}"/>
</Grid>
</Grid>
</UserControl>
I've stripped out some layout and look-n-feel related properties to not bother you (you can see the full code in the attached sample). Two value converters here are used to nicely present "completed" tasks. A completed task is shown in gray with a strikethrough text decoration (there is no native support for strikethrough text decoration in Silverlight, thus a little trick with Line
). The tooltip shows the date when the task was created and completed.
The code-behind is very simple. It just creates the corresponding instance of the view model class and sets it as the DataContext
. Afterwards, it signals the ViewModel to execute first-time initialization by calling its Activate()
method.
public partial class TaskManagementView
{
public TaskManagementView()
{
InitializeComponent();
}
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
var viewModel = new TaskManagementViewModel();
DataContext = viewModel;
viewModel.Activate();
}
private void DescriptionTextChanged(object sender, TextChangedEventArgs e)
{
((TextBox) sender).GetBindingExpression(TextBox.TextProperty).UpdateSource();
}
}
By default, the TextBox
control updates the bound value when it loses focus, so here I'm using an event handler to force an immediate update. Now, let's see the most interesting part - the ViewModel.
public class TaskManagementViewModel : ViewModelBase
{
Task selected;
string description;
public TaskManagementViewModel()
{
InitializeProperties();
InitializeCommands();
}
void InitializeProperties()
{
Tasks = new ObservableCollection<Task>();
}
void InitializeCommands()
{
var cmd = new ViewModelCommandBuilder(this);
CreateCommand = cmd.For(()=> Create());
DeleteCommand = cmd.For(()=> Delete());
MarkCompleteCommand = cmd.For(()=> MarkComplete());
}
public ICommand CreateCommand
{
get; private set;
}
public ICommand MarkCompleteCommand
{
get; private set;
}
public ICommand DeleteCommand
{
get; private set;
}
public ObservableCollection<Task> Tasks
{
get; private set;
}
public Task Selected
{
get { return selected; }
set
{
selected = value;
NotifyOfPropertyChange(() => Selected);
NotifyOfPropertyChange(() => CanDelete);
NotifyOfPropertyChange(() => CanMarkComplete);
}
}
public string Description
{
get { return description; }
set
{
description = value;
NotifyOfPropertyChange(() => Description);
NotifyOfPropertyChange(() => CanCreate);
}
}
public void Activate()
{
foreach (Task each in all)
{
Tasks.Add(each);
}
Selected = Tasks[0];
}
public void Create()
{
Tasks.Insert(0, newTask);
Selected = newTask;
Description = "";
}
public bool CanCreate
{
get { return !string.IsNullOrEmpty(Description); }
}
public void MarkComplete()
{
Replace(Selected, updatedTask);
Selected = updatedTask;
}
public bool CanMarkComplete
{
get { return Selected != null && !Selected.IsCompleted; }
}
void Replace(Task prevTask, Task newTask)
{
var position = Tasks.IndexOf(prevTask);
Tasks.RemoveAt(position);
Tasks.Insert(position, newTask);
}
public void Delete()
{
Tasks.Remove(Selected);
if (Tasks.Count > 0)
Selected = Tasks[0];
}
public bool CanDelete
{
get { return Selected != null; }
}
}
This is really straightforward code; the only parts requiring explanations are the ViewModelBase
base class and the initialization of the commands. I've took both ideas from Rob Eisenberg's beautiful "Build your own MVVM framework" presentation which I recommend to everyone doing Silverlight/WPF development. The ViewModelBase
class is dead simple:
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged = delegate { };
public void NotifyOfPropertyChange(string propertyName)
{
Call.OnUIThread(() => PropertyChanged(this, new PropertyChangedEventArgs(propertyName)));
}
public void NotifyOfPropertyChange<TProperty>(Expression<Func<TProperty>> property)
{
var lambda = (LambdaExpression) property;
MemberExpression memberExpression;
if (lambda.Body is UnaryExpression)
{
var unaryExpression = (UnaryExpression)lambda.Body;
memberExpression = (MemberExpression)unaryExpression.Operand;
}
else
{
memberExpression = (MemberExpression) lambda.Body;
}
NotifyOfPropertyChange(memberExpression.Member.Name);
}
}
It implements the usual INotifyPropertyChanged
infrastructure, and allows you to have strongly-typed property notifications (instead of mangling with strings). Also because the PropertyChanged
event can be raised from asynchronous code (i.e., raised from a different thread than main), it needs to be dispatched to the main thread, which is done by using a simple utility class Call
and its OnUIThread()
routine.
public static class Call
{
public static void OnUIThread(Action action)
{
Dispatcher dispatcher = Deployment.Current.Dispatcher;
if (dispatcher.CheckAccess())
{
action();
return;
}
dispatcher.BeginInvoke(action);
}
}
The commands in WPF/Silverlight are represented by the ICommand
class with the following interface:
public interface ICommand
{
bool CanExecute(object parameter);
void Execute(object parameter);
event EventHandler CanExecuteChanged;
}
To not bother defining the implementation of this interface for every possible command, Rob suggested using methods defined in the ViewModel. So instead of having an implementation class for every command, there is only one general-purpose class, and every instance of it is bound (via Reflection) to the specified method. When the command is executed, the bound method is called. Also, by simple convention, if there is a property in the ViewModel which has the same name as the command method but prefixed with "Can", it will be used to monitor the CanExecute
status of the command. This is done by utilizing the same INotifyPropertyChanged
infrastructure:
public class ViewModelCommandBuilder
{
readonly ViewModelBase viewModel;
public ViewModelCommandBuilder(ViewModelBase viewModel)
{
this.viewModel = viewModel;
}
public ICommand For(Expression<Action> expression)
{
var methodCall = (MethodCallExpression)expression.Body;
return new ViewModelCommand(viewModel, methodCall.Method,
viewModel.GetType().GetProperty("Can" + methodCall.Method.Name));
}
}
public class ViewModelCommand : ICommand
{
readonly MethodInfo execute;
readonly PropertyInfo canExecute;
readonly ViewModelBase viewModel;
public event EventHandler CanExecuteChanged = delegate { };
public ViewModelCommand(ViewModelBase viewModel, MethodInfo execute, PropertyInfo canExecute)
{
this.viewModel = viewModel;
this.execute = execute;
this.canExecute = canExecute;
ObserveCanExecuteChanged();
}
void ObserveCanExecuteChanged()
{
if (canExecute == null)
return;
viewModel.PropertyChanged += (s, e) =>
{
if (e.PropertyName == canExecute.Name)
CanExecuteChanged(this, EventArgs.Empty);
};
}
public bool CanExecute(object parameter)
{
return canExecute == null || (bool) canExecute.GetValue(viewModel, null);
}
public void Execute(object parameter)
{
execute.Invoke(viewModel, null);
}
}
It's elegant and quite a simple solution to commanding. It greatly reduces the amount of code we need to write to support commanding with MVVM pattern in WPF/Silverlight. In the sample application, the following method/property pairs are registered and used for commanding:
Create/CanCreate
MarkComplete/CanMarkComplete
Delete/CanDelete
That is probably everything you need to know about the sample application. I'll be carrying this sample solution throughout this article, and will use it for the next articles as well (please make sure you understand it before we move to advanced topics).
So, let's get back to the main course. As you can see, there are some gaps (marked as TODO) left in the sample code that I'll try to fill, by experimenting with various approaches to handle asynchronous calls of WCF services in Silverlight.
The ceremony
As you remember from my previous article, I'm not a big fan of static service proxy generation, and as it was previously discovered, we can get rid of that rudiment by simply creating an asynchronous twin interface. So according to rules I've outlined in the previous article, the asynchronous interface for our ITaskService
should look like the one below:
[ServiceContract(Name = "ITaskService")]
public interface ITaskServiceAsync
{
[OperationContract(AsyncPattern = true)]
IAsyncResult BeginGetAll(AsyncCallback callback, object state);
Task[] EndGetAll(IAsyncResult result);
[OperationContract(AsyncPattern = true)]
IAsyncResult BeginCreate(string description, AsyncCallback callback, object state);
Task EndCreate(IAsyncResult result);
[OperationContract(AsyncPattern = true)]
IAsyncResult BeginMarkComplete(Guid id, AsyncCallback callback, object state);
Task EndMarkComplete(IAsyncResult result);
[OperationContract(AsyncPattern = true)]
IAsyncResult BeginDelete(Guid id, AsyncCallback callback, object state);
void EndDelete(IAsyncResult result);
}
This interface is only used on the Silverlight side, but I've found it convenient to keep it together with a synchronous interface in the same file as it makes maintenance easier. Also, we need to link the Task
entity class definition in the Silverlight project.
To open a WCF channel, we need to create the ChannelFactory
for the asynchronous interface and point it to our normal synchronous service implementation:
var factory = new ChannelFactory<ITaskServiceAsync>(
new BasicHttpBinding(),
new EndpointAddress("http://localhost/SampleSilverlightWCF/Services/TaskService.svc"));
The channel factory should be created only once, and then reused for every service call (every time we need to call the service, we need to open the new channel again). The ViewModel's constructor fits well for this scenario:
public class TaskManagementViewModel : ViewModelBase
{
ChannelFactory<ITaskServiceAsync> factory;
...
public TaskManagementViewModel()
{
InitializeFactory();
InitializeProperties();
InitializeCommands();
}
void InitializeFactory()
{
factory = new ChannelFactory<ITaskServiceAsync>(
new BasicHttpBinding(),
new EndpointAddress("http://localhost/SampleSilverlightWCF/Services/TaskService.svc"));
}
...
Now, let's take the Activate()
method as the example and investigate how its code may look like, trying different approaches to handle the asynchronous calls of the WCF service.
public void Activate()
{
foreach (Task each in all)
{
Tasks.Add(each);
}
Selected = Tasks[0];
}
Asynchronous Programming Model (APM)
This is the most straightforward one, and it should be familiar to everyone who at least once tried asynchronous programming in .NET. In APM, asynchronous operations are represented by a pair of BeginXXX/EndXXX
methods, and it requires you to pass a completion callback delegate to the BeginXXX
method:
public void Activate()
{
ITaskServiceAsync service = factory.CreateChannel();
service.BeginGetAll(ar =>
{
try
{
var all = service.EndGetAll(ar);
foreach (Task each in all)
{
Tasks.Add(each);
}
Selected = Tasks[0];
}
catch (FaultException exc)
{
}
}, null);
}
This callback delegate will be called by the asynchronous method when the operation completes. Then inside this callback, you could get the result, and you also need to handle any exceptions thrown. There are a few issues with this coding pattern:
- The reversed code structure looks odd
- Additional parameters and symbols add noise
- Boilerplate exception handling code
In this simple example, the code doesn't look extremely bad, regarding issues 1 and 2, but try nesting a few other asynchronous calls, and the code will become very ugly. You can try to apply DRY to 3 to some degree, but only by increasing the effects of 2.
Reactive Extensions (RX)
Everyone is screaming that by using RX, you may greatly simplify code which deals with asynchronous method calls, and how sexy it is for this task. Let's see:
public void Activate()
{
ITaskServiceAsync service = factory.CreateChannel();
Func<IObservable<Task[]>> method =
Observable.FromAsyncPattern<Task[]>(service.BeginGetAll, service.EndGetAll);
method.Invoke().Subscribe(
result =>
{
foreach (Task each in result)
{
Tasks.Add(each);
}
Selected = Tasks[0];
},
exception =>
{
}
);
}
OK, it removes the try-catch
handler, and instead, you can subscribe to the onError
callback. Awesome. This is really a fantastic improvement (which comes with the cost of additional symbol noise). Is it just for me, or is RX-based code really doesn't look any better than APM? The code still suffers from the same reversed code structure, and if you'll try nesting another asynchronous call, the code will look even harder to read than not using RX at all (especially if your code conventions include such antics as compulsory use of "this.
" and the underscore prefix for fields). In fact, I saw this enough on a real-world project, where the code that uses RX for asynchronous pattern handling was nothing more than an infinitely tangled mess of lambdas and special symbols (=>_.()
). It was looking exactly like a cryptogram.
Update: I'm not alone. It seems like Sacha Barber has arrived at a similar conclusion for RX here.
GoF Command Pattern
This is probably the latest trend which I constantly see in Silverlight applications and samples related to the consumption of asynchronous services. The idea is quite simple - represent each service method call as an object of its own. Remember the description of the GoF Command Pattern? From Wikipedia:
In object-oriented programming, the Command pattern is a Design Pattern in which an object is used to represent and encapsulate all the information needed to call a method at a later time. This information includes the method name, the object that owns the method, and values for the method parameters.
Basically, every input parameter and call result corresponds to a property. The client code just creates an instance of a command, fills in the property values, and executes the command; afterwards, it gets the result of the command execution and proceeds further. The command object hides all the ugly asynchronous plumbing code, and allows factoring out common code (like exception handling). The variation on this theme is having a single class for all service commands, representing each as a method that takes a completion callback. For example, this style is used by Michael Washington in his CodeProject articles.
Let's implement the command for the GetAll()
service method and see how the code of the Activate()
method will look like:
public void Activate()
{
var cmd = new GetAllTaskServiceCommand(factory);
cmd.Execute(() =>
{
if (cmd.Failed)
{
return;
}
foreach (Task each in cmd.Result)
{
Tasks.Add(each);
}
Selected = Tasks[0];
});
}
In my opinion, now it looks clean. Now the actual command object:
public class GetAllTaskServiceCommand
{
readonly ChannelFactory<ITaskServiceAsync> factory;
public GetAllTaskServiceCommand(ChannelFactory<ITaskServiceAsync> factory)
{
this.factory = factory;
}
public Exception Exception
{
get; private set;
}
public bool Failed
{
get { return Exception != null; }
}
public Task[] Result
{
get; private set;
}
public void Execute(Action complete)
{
ITaskServiceAsync service = factory.CreateChannel();
service.BeginGetAll(ar =>
{
try
{
Result = service.EndGetAll(ar);
}
catch (FaultException exc)
{
Exception = exc;
}
complete();
}, null);
}
}
Not bad. We can factor out some common code ... but not much.
public abstract class ServiceCommand<T>
{
public Exception Exception
{
get; protected set;
}
public bool Failed
{
get { return Exception != null; }
}
public T Result
{
get; protected set;
}
public void Execute(Action complete)
{
BeginExecute(ar =>
{
try
{
EndExecute(ar);
}
catch (FaultException exc)
{
Exception = exc;
}
complete();
});
}
protected abstract void BeginExecute(AsyncCallback callback);
protected abstract void EndExecute(IAsyncResult asyncResult);
}
public class GetAllTaskServiceCommand : ServiceCommand<Task[]>
{
readonly ChannelFactory<ITaskServiceAsync> factory;
ITaskServiceAsync service;
public GetAllTaskServiceCommand(ChannelFactory<ITaskServiceAsync> factory)
{
this.factory = factory;
}
protected override void BeginExecute(AsyncCallback callback)
{
service = factory.CreateChannel();
service.BeginGetAll(callback, null);
}
protected override void EndExecute(IAsyncResult asyncResult)
{
Result = service.EndGetAll(asyncResult);
}
}
While I like how the client code (the Activate()
method) looks, I feel like I've only moved complexity to another place. Also, this approach will require creating a command class for every service call, which is boring.
Turn on the light
Fixing the root cause
I experimented with almost all possible approaches, claiming to simplify asynchronous programming (even with very exotic ones that I haven't listed here), and wasn't satisfied with any. All that time, I was feeling like I was trying to cure the effects of a disease instead of fixing its root cause. All that complexity comes from the fact that we need to explicitly deal with an asynchronous interface. Its consumption is hard to generalize, and it comes with the cost of manual maintenance (every time you change the synchronous interface, you need to amend its twin brother). But what if I somehow manage to transparently handle this asynchrony? Can I completely eliminate the need to explicitly deal with the asynchronous interface? I want to make my client code free from that asynchronous beast.
Once this idea popped up in my head, I quickly came up with the following design:
An hour later, I was having a fully workable Reflection-based solution. It was ugly, but did the job quite good. I was using a string to specify what method I wanted to call, and was having a generic method which accepts an array of parameter values. Then, by using Reflection, I was getting a BeginXXX\EndXXX
method pair and using it to make the actual call. The approach taken wasn't ideal; the bad things are: no type-safety and not refactoring friendly.
Every time I see strings being used for such scenarios, I always recall that we (developers using .NET 3.5 and higher) have better ways to approach them. Expression Trees to the rescue! Another hour later, after a few refactoring cycles, I finally arrived at the design and implementation I was totally satisfied with.
Type-safety (compile time checking) dictated the need to differentiate calls made to void service methods and to the service methods that return results. Let's see the actual implementation, starting from the base class:
public abstract class ServiceCall<TServiceAsync>
{
readonly ChannelFactory<TServiceAsync> factory;
readonly MethodCallExpression call;
TServiceAsync channel;
Action callback;
protected ServiceCall(ChannelFactory<TServiceAsync> factory, MethodCallExpression call)
{
this.factory = factory;
this.call = call;
}
public bool Failed
{
get { return Exception != null; }
}
public Exception Exception
{
get; private set;
}
public void Execute(Action onComplete)
{
callback = onComplete;
channel = factory.CreateChannel();
object[] parameters = BuildParameters();
MethodInfo beginMethod = GetBeginMethod();
beginMethod.Invoke(channel, parameters);
}
MethodInfo GetBeginMethod()
{
return GetMethod("Begin" + call.Method.Name);
}
MethodInfo GetEndMethod()
{
return GetMethod("End" + call.Method.Name);
}
static MethodInfo GetMethod(string methodName)
{
return typeof(TServiceAsync).GetMethod(methodName);
}
object[] BuildParameters()
{
var parameters = new List<object>();
foreach (Expression argument in call.Arguments)
{
object parameter = Expression.Lambda(argument).Compile().DynamicInvoke();
parameters.Add(parameter);
}
parameters.Add(new AsyncCallback(OnCallCompleted));
parameters.Add(null);
return parameters.ToArray();
}
void OnCallCompleted(IAsyncResult ar)
{
try
{
MethodInfo endMethod = GetEndMethod();
HandleResult(endMethod.Invoke(channel, new object[]{ar}));
}
catch (Exception exc)
{
Exception = exc;
}
Call.OnUIThread(callback);
}
protected abstract void HandleResult(object result);
}
When the command is executed, from MethodCallExpression
, we deduce the method name and extract the parameters passed to it. Because the parameters can be any expression, not just constants, we need to actually evaluate them. Then, we find the BeginXXX
method on the asynchronous interface, create a channel, and use it to service the call. When the call is completed, we again look for the EndXXX
method and use it to complete the call. Then, we signal the client about call completion by using the supplied callback (firstly dispatching the execution to the main thread). Rest of the code is pretty simple and self-explanatory:
public class ServiceCommand<TService, TServiceAsync> : ServiceCall<TServiceAsync>
{
public ServiceCommand(ChannelFactory<TServiceAsync> factory, Expression<Action<TService>> call)
: base(factory, (MethodCallExpression) call.Body)
{}
protected override void HandleResult(object result)
{
}
}
public class ServiceQuery<TResult, TService, TServiceAsync> : ServiceCall<TServiceAsync>
{
public ServiceQuery(ChannelFactory<TServiceAsync> factory, Expression<Func<TService, TResult>> call)
: base(factory, (MethodCallExpression) call.Body)
{}
public TResult Result
{
get; private set;
}
protected override void HandleResult(object result)
{
Result = (TResult) result;
}
}
Now, let's see how the client code looks. For service methods which return results:
public void Activate()
{
var action = new ServiceQuery<Task[], ITaskService, ITaskServiceAsync>(factory,
service => service.GetAll());
action.Execute(() =>
{
Task[] all = action.Result;
foreach (Task each in all)
{
Tasks.Add(each);
}
Selected = Tasks[0];
});
}
For service methods which don't return results (void
):
public void Delete()
{
var action = new ServiceCommand<ITaskService, ITaskServiceAsync>(factory,
service => service.Delete(Selected.Id));
action.Execute(() =>
{
Tasks.Remove(Selected);
if (Tasks.Count > 0)
Selected = Tasks[0];
});
}
That's cool. We've got full compile-time checking; don't need to bother creating a class for every service method, and we don't need to deal with dirty asynchronous plumbing. Everything is done in a completely transparent manner.
Hiding construction complexity behind the Builder
If you pay attention to the client code, you can see that it's doing the same things repeatedly: constructs the command, specifies a lambda expression, and executes it. Most of the code is actually related to the construction. And that construction code is highly recurring. To construct a command or query, every method in our ViewModel specifies the same set of things - synchronous interface, asynchronous interface, and factory. In my opinion, that construction code takes a lot of the screen real estate, increases typing, and what's more important - it distracts from the main thing, the actual service call and its parameters.
When I encounter this kind of design annoyances, I usually deploy the Builder pattern to fix them. From the Builder pattern definition (Consequences section):
It isolates code for construction and representation. The Builder pattern improves modularity by encapsulating the way a complex object is constructed and represented. Clients needn't know anything about the classes that define the product's internal structure; such classes don't appear in the Builder's interface.
The key thing here is: "It encapsulates the way a complex object is constructed and represented". We can encapsulate how the service commands and queries are constructed and initialized behind a convenient interface.
public class ServiceCallBuilder<TService, TServiceAsync> where TService : class
{
readonly ChannelFactory<TServiceAsync> factory;
public ServiceCallBuilder(ChannelFactory<TServiceAsync> factory)
{
this.factory = factory;
}
public ServiceCommand<TService, TServiceAsync> Command(Expression<Action<TService>> call)
{
return new ServiceCommand<TService, TServiceAsync>(factory, call);
}
public ServiceQuery<TResponse, TService, TServiceAsync> Query<TResponse>(Expression<Func<TService, TResponse>> call)
{
return new ServiceQuery<TResponse, TService, TServiceAsync>(factory, call);
}
}
Let's see how the client code has changed when using the builder.
public class TaskManagementViewModel : ViewModelBase
{
ServiceCallBuilder<ITaskService, ITaskServiceAsync> build;
...
public TaskManagementViewModel()
{
InitializeServices();
...
}
void InitializeServices()
{
var factory = new ChannelFactory<ITaskService>(
new BasicHttpBinding(),
new EndpointAddress("http://localhost/SampleSilverlightWCF/Services/TaskService.svc"));
build = new ServiceCallBuilder<ITaskService, ITaskServiceAsync>(factory);
}
...
public void Activate()
{
var action = build.Query(service => service.GetAll());
action.Execute(() =>
{
Task[] all = action.Result;
foreach (Task each in all)
{
Tasks.Add(each);
}
Selected = Tasks[0];
});
}
public void Delete()
{
var action = build.Command(service => service.Delete(Selected.Id));
action.Execute(() =>
{
Tasks.Remove(Selected);
if (Tasks.Count > 0)
Selected = Tasks[0];
});
}
Here we're creating the builder once, on initialization, and then we use it to conveniently build commands/queries. If you compare with the previous code, the difference in clarity is huge.
Emitting an asynchronous interface
After we've insulated the client code from explicit interaction with the asynchronous interface, we opened up the possibility to simplify the solution further. Recalling from my previous article, this asynchronous twin interface is only used by the Silverlight application. We don't need it on the server-side either. We also know the rules by which this asynchronous interface should be built. So why bother manually creating and maintaining it? We can simply generate it from the definition of its synchronous counterpart. Sounds like a perfect scenario for Reflection.Emit
.
We'll require from client code, only the type of synchronous interface, and perhaps some configuration values (like the endpoint address); the creation of channel factory will be handled internally.
public class TaskManagementViewModel : ViewModelBase
{
const string address = "http://localhost/SampleSilverlightWCF/Services/TaskService.svc";
ServiceCallBuilder<ITaskService> build;
...
public TaskManagementViewModel()
{
InitializeServices();
...
}
void InitializeServices()
{
build = new ServiceCallBuilder<ITaskService>(address);
}
...
public class ServiceCallBuilder<TService> where TService : class
{
readonly ServiceChannelFactory<TService> factory;
public ServiceCallBuilder(string address)
{
factory = new ServiceChannelFactory<TService>(new EndpointAddress(address));
}
...
The ServiceChannelFactory
class is responsible for the actual channel factory construction and the service channel creation.
public class ServiceChannelFactory<TService>
{
dynamic channelFactory;
public ServiceChannelFactory(EndpointAddress address)
{
BuildChannelFactory(address);
}
void BuildChannelFactory(EndpointAddress address)
{
channelFactory = Activator.CreateInstance(GetChannelFactoryType(), new BasicHttpBinding(), address);
}
static Type GetChannelFactoryType()
{
Type type = AsyncServiceInterfaceFactory.Instance.Generate(typeof(TService));
return typeof(ChannelFactory<>).MakeGenericType(type);
}
public object CreateChannel()
{
return channelFactory.CreateChannel();
}
}
ServiceChannelFactory
in its turn uses AsyncServiceInterfaceFactory
to generate the definition of the asynchronous interface. AsyncServiceInterfaceFactory
is the singleton that does generate and cache the created type definitions; already generated type definitions will be reused on subsequent calls. I won't show the code for the AsyncServiceInterfaceFactory
class and the actual emitting of the interface definition; it's a pretty standard Reflection.Emit
stuff (you can see it in full detail in the attached sample project). The end-result - we don't need to manually create and maintain the definition of the asynchronous twin interface anymore. We've arrived to the heaven called "Frictionless WCF services consumption in Silverlight". But are we there yet?
The greatest illusion
While I was totally satisfied with the results, there was still something preventing my sleep. The reversed code structure was still looking odd. But I was ignoring that oddity without remorse; I've removed all of the friction, and the code was looking really good to me.
Until there appeared the need to make two sequential service calls. The second call was dependent upon the results obtained from the execution of the first call, so the nesting of calls was required. It was looking like the code below:
public void Activate()
{
var authentication = build.Query(service => service.Authenticate(login, password));
authentication.Execute(() =>
{
if (!authentication.Result.Success)
return;
User user = authentication.Result.User;
var query = build.Query(service => service.GetIssues(user));
query.Execute(() =>
{
foreach (Issue each in query.Result)
{
Issues.Add(each);
}
});
});
}
Not so bad actually. It's still readable, just adds some indentation.
But the real trouble began when I tried to execute a few service calls in parallel, waited until all of them completed, and only then proceeded with the execution (it's a typical fork/join scenario). I experienced a total setback. I was forced to use some global fields to keep the current state, and the code flow was really fuzzy. Mess returned.
And this was only the tip of the iceberg. Imagine what code we'll need to write for polling scenarios. Because of the inverted control flow, we can't use the usual looping constructs like "while
". We'll need to write some helper class to control the loop, to track the current state, and to provide additional synchronization. We'll need to write our own control mechanism. And while we can lean to some degree on a control mechanism by utilizing TPL - it will not remove the ugliness. In this case, TPL is just a trade of one mess to another.
So, it looks like despite everything I did up to this point, it was actually an illusion of solution. The root cause is still unfixed. But how can we fix it? The reversed code structure which comes from the inversion of control imposed by the APM callback delegate was recognized by me as unavoidable. Without any doubt, I've been thinking it's the consequence inherent to asynchronous programming. Until I met coroutines ...
Coroutines - the missing piece of the puzzle
I was surfing through Caliburn's documentation when I first saw the use of coroutines. I didn't get it until the second time Rob described coroutines as the approach that can simplify asynchronous programming. He has shown this in his beautiful "Build your own MVVM framework" presentation which I've already mentioned.
The idea is simple as everything genius. But let's first see a few descriptions from Wikipedia about coroutines:
In Computer Science, coroutines are program components that generalize subroutines to allow multiple entry points for suspending and resuming execution at certain locations
Ehh, that's too smart for me. Let's see another one:
Subroutines can return only once; in contrast, coroutines can return (yield) several times. The start of a coroutine is the first point of entry, and subsequent points of entry are following yield commands. Practically, yielding returns the result to the calling coroutine, and gives it back control, like a usual subroutine. However, the next time the coroutine is called, the execution does not start at the beginning of the coroutine, but just after the yield call.
OK, this sounds familiar. I'm sure every C# developer knows what the yield
(http://msdn.microsoft.com/en-us/library/dscyy5s0.aspx) keyword is used for and how iterator blocks generally work. Here, the most important property of the iterator block is the ability to temporarily transfer control to the caller (exactly what coroutines do).
Rob has supremely exploited this ability. He has built his own clever generic control mechanism on top of the iterator block. By inverting control over completion of the asynchronous operation, he has reversed the structure of the code back to its sequential form. The compiler provided the rest of the magic (like keeping the current state and pausing/resuming the execution automatically). Let's see how it's done.
The inversion of control is simple. Instead of taking (in) the callback delegate, the asynchronous operation should rather signal completion by raising an event (out). This is the Event-based asynchronous pattern (EAP). And in fact, it was introduced in .NET framework 2.0.
This single change, of course, doesn't magically free the client code from control over the asynchronous operation completion. And this is where the generic control mechanism written by Rob comes into play.
public class Yield
{
readonly IEnumerator<IAction> iterator;
Yield(IEnumerable<IAction> routine)
{
iterator = routine.GetEnumerator();
}
void Iterate()
{
ActionCompleted(null, EventArgs.Empty);
}
void ActionCompleted(object sender, EventArgs args)
{
var previous = sender as IAction;
if (previous != null)
previous.Completed -= ActionCompleted;
if (!iterator.MoveNext())
return;
IAction next = iterator.Current;
next.Completed += ActionCompleted;
next.Execute();
}
public static void Call(IEnumerable<IAction> routine)
{
new Yield(routine).Iterate();
}
}
It takes routine (the sequence of IAction
elements), and gains control over its iteration. While iterating, it executes each IAction
, and advances to the next one only when the action is actually completed - this could be on a different thread. Basically, completion of the operation is what actually moves the iterator.
The IAction
interface represents the operation that needs to be executed, and it's very simple.
public interface IAction
{
void Execute();
event EventHandler Completed;
}
Now to be able to utilize this mechanism, we need to use an iterator block for methods which use asynchronous operations. Let's see how this changes client code.
public IEnumerable<IAction> Activate()
{
var action = build.Query(service => service.GetAll());
yield return action;
foreach (Task each in action.Result)
{
Tasks.Add(each);
}
Selected = Tasks[0];
}
...
public IEnumerable<IAction> Delete()
{
var action = build.Command(service => service.Delete(Selected.Id));
yield return action;
Tasks.Remove(Selected);
if (Tasks.Count > 0)
Selected = Tasks[0];
}
As you can see, the code structure exhibits the sequential nature of synchronous code. But don't be fooled, the operations are still asynchronous. It's just an illusion of synchrony, perhaps the greatest illusion.
In order to execute this iterator block correctly, we need to run it using the control mechanism above. All of the command methods are executed by the ViewModelCommand
class, so we need to change it a bit.
public class ViewModelCommand : ICommand
{
...
public void Execute(object parameter)
{
object returnValue = execute.Invoke(viewModel, null);
if (returnValue != null)
HandleReturnValue(returnValue);
}
private static void HandleReturnValue(object returnValue)
{
var routine = returnValue as IEnumerable<IAction>;
if (routine != null)
Yield.Call(routine);
}
}
The last change is to the execution of the Activate()
method ...
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
var viewModel = new TaskManagementViewModel();
DataContext = viewModel;
Yield.Call(viewModel.Activate());
}
... and now we've finally arrived to the heaven of "Frictionless WCF service consumption in Silverlight". Let's see how this approach will let us handle different asynchronous programming scenarios.
Footnote: If you didn't get why and how all this works, I suggest reading this article by Tomas Petricek, which has clean and detailed technical explanations on inversion of control in asynchronous programming and coroutines in C#. Also, Rob and Jeremy have posted on coroutines recently (here and here).
Dependent calls
Before:
public void Activate()
{
var authentication = build.Query(service => service.Authenticate(login, password));
authentication.Execute(() =>
{
if (!authentication.Result.Success)
return;
var user = action.Result.User;
var query = build.Query(service => service.GetIssues(user));
query.Execute(() =>
{
foreach (Issue each in query.Result)
{
Issues.Add(each);
}
});
});
}
After:
public IEnumerable<IAction> Activate()
{
var action = build.Query(service => service.Authenticate(login, password));
yield return action;
if (!action.Result.Success)
yield break;
var user = action.Result.User;
action = build.Query(service => service.GetIssues(user));
yield return action;
foreach (Issue each in action.Result)
{
Issues.Add(each);
}
}
Looks exactly how it should - one call after another, sequentially.
Fork/Join
Imagine that we need to call some weather service which can return weather conditions only for a single city. But we need to obtain weather for two cities simultaneously, and then, for whatever reasons, we need to do something with accumulated results.
The IAction
interface represents a single operation. We can change our control mechanism to accept an array of IAction
s, but this will complicate it greatly, and will also reduce the clarity of client code. Instead, we have a better solution at our disposal - the GoF's Composite pattern.
public static class Parallel
{
public static IAction Actions(params IAction[] actions)
{
return new ParallelActions(actions);
}
private class ParallelActions : IAction
{
public event EventHandler Completed;
readonly IAction[] actions;
int remaining;
public ParallelActions(IAction[] actions)
{
this.actions = actions;
}
public void Execute()
{
remaining = actions.Length;
foreach (IAction action in actions)
{
action.Completed += delegate
{
if (Interlocked.Decrement(ref remaining) == 0)
SignalCompleted();
};
action.Execute();
}
}
void SignalCompleted()
{
EventHandler handler = Completed;
if (handler != null)
Call.OnUIThread(() => handler(this, EventArgs.Empty));
}
}
}
The composite takes a batch of actions, then executes each, and signals about the completion only when all of the actions are completed.
public IEnumerable<IAction> GetWeather()
{
var kyiv = build.Query(service => service.GetWeather("Kyiv"));
var sydney = build.Query(service => service.GetWeather("Sidney"));
yield return Parallel.Actions(kyiv, sydney);
if (kyiv.Result.Temperature > sydney.Result.Temperature)
MessageBox.Show("It's summer in Kyiv");
}
This will execute two asynchronous calls in parallel, and the execution will continue only after both of them are completed.
Asynchronous polling
Say, we need to periodically poll the weather service in order to show the latest weather conditions (we can have some cool weather widget which updates itself every hour). We can do it pretty easily:
public IEnumerable<IAction> PollWeather()
{
while (true)
{
var query = build.Query(service => service.GetWeather("Kyiv"));
yield return query;
WeatherConditions weather = query.Result;
widget.Update(weather);
Thread.Sleep(TimeSpan.FromHours(1));
}
}
The problem is that we cannot actually use Thread.Sleep
here as it'll block the main thread. Neither can we directly use the Timer
class, because as soon as the timer is started, the control is lost and the loop is restarted. Instead, we need to repeat the trick and implement another clever action class.
public static class Sleep
{
public static IAction Timeout(TimeSpan timeout)
{
return new SleepAction(timeout);
}
private class SleepAction : IAction
{
readonly TimeSpan timeout;
readonly Timer timer;
public event EventHandler Completed;
public SleepAction(TimeSpan timeout)
{
this.timeout = timeout;
timer = new Timer(OnTimeout);
}
public void Execute()
{
timer.Change(timeout, TimeSpan.FromMilliseconds(-1));
}
void OnTimeout(object state)
{
timer.Dispose();
SignalCompleted();
}
void SignalCompleted()
{
EventHandler handler = Completed;
if (handler != null)
Call.OnUIThread(() => handler(this, EventArgs.Empty));
}
}
}
public IEnumerable<IAction> PollWeather()
{
while (true)
{
...
yield return Sleep.Timeout(TimeSpan.FromHours(1));
}
}
Another scenario is when you need to asynchronously poll some service and end the polling when some condition is met. You can easily do this with the help of the yield break
keyword.
public IEnumerable<IAction> TrackOrderStatus(Guid orderId)
{
while (true)
{
var status = build.Query(service => service.GetOrderStatus(orderId));
yield return status;
if (status.Result.Confirmed)
{
MessageBox.Show("You order has just been confirmed");
yield break;
}
yield return Sleep.Timeout(TimeSpan.FromSeconds(5));
}
}
Finale
Adding more convenience
If you have a lot of views which communicate with the server-side (pretty common case for enterprise apps) through WCF services (usually, there is only a single type of service used throughout the view), you can remove code duplication and even improve code clarity further by moving the common action construction code in to the generic base class. Then the client code may look like the one below:
public IEnumerable<IAction> GetWeather()
{
var kyiv = Query(service => service.GetWeather("Kyiv"));
var sydney = Query(service => service.GetWeather("Sidney"));
yield return Parallel(kyiv, sydney);
if (kyiv.Result.Temperature < sydney.Result.Temperature)
MessageBox.Show("It's summer in Sydney");
}
Dense and evident.
Conclusion
It was a lengthy article, and I hope it was well worth your time. We have removed all of the friction introduced by the asynchronous consumption requirement for WCF services in Silverlight. The ability to use a plain synchronous interface and the introduction of coroutines opened up the possibilities to simplify unit testing harnesses for otherwise difficult to test asynchronous code. In the next article, I'll show you how to test-drive logic of ViewModels which use asynchronous service calls, and how the solution above aids in unit testing. If you still have trouble understanding how everything is stitched, just download the sample application and play with it. That's probably the best way to get a firm understanding of the approach.
The latest version of the source code could be found here. Additional material related to the topic I'll be posting on my blog.
Caveats
There are some minor restrictions for the body of the iterator block, and also, don't forget to run you coroutine methods through Yield.Call
, and have fun!
History
- May 17, 2011
- Migrated sample application to use local web server instead of IIS
- Fixed code formatting
- Changed API in code examples to better reflect the latest Servelat.Pieces project API