The Asynchronous Command Pattern for HTTP in Silverlight and GWT
When you’re writing RIA applications in an environment like Silverlight or GWT, you’re restricted to doing asynchronous http calls to the server — this leaves you with a number of tricky choices, such as, where to put your callback functions. To be specific, imagine we’ve created a panel in the user interface where a user enters information, then clicks on a form to submit it. The first place you might think of putting the callback is in the class for the panel, something like
public class MyPanel:StackPanel { ... other functions ... void SubmitButton_Click(Object sender,EventArgs e) { ... collect data from forms ... ServerWrapper.DoSubmission(formData,SubmissionCallback); } void SubmissionCallback(SubmissionResult result) { ... update user interface ...
}
}
(Although code samples are in C#, the language I’m using now, I developed this pattern when working on a Java project.) This is a straightforward pattern for the simplest applications, but it runs out of steam when your application becomes more complex. It can become confusing to keep track of your callback functions when your object does more than one kind of asynchronous call: for instance, if it has multiple buttons. If the same action can be done on the server from more than one place in the UI, it’s not clear where the callback belongs.
One answer to the problem is to use the Command Pattern, to organize asynchronous activities into their own classes that contain both the code that initiates an asynchronous request and the callback that runs when the request completes.
The Command Pattern turns a verb into a noun — it turns a method into an object. Commands implement an interface like
public interface ICommand { void Execute(); }
The parameters of a Command can be set in it’s constructor, or can be set by setting properties on the Command — setting parameters in the constructor is less error prone, although when you’ve got twenty or so optional parameters, it’s a lot easier to use properties. In this case, we’ll organize the code like so
public class SubmitFormCommand:ICommand { private FormData Data;
public SubmitFormCommand(FormData data) { Data=data; }
public void Execute() { ... processing ... ServerWrapper.DoSubmission(Data,Callback); } public void Callback(SubmissionResult result) { ... update user interface ... } }
The code in the Click handler now looks like this:
void SubmitButton_Click(Object sender,EventArgs e) { ... collect data from forms ...
ICommand action=new SubmitFormCommand(formData); action.Execute() }
It makes sense to demarcate Commands so that they can be obviously distinguished from other classes: I like to always have ‘Command’ at the end of the class name and I like to keep them in a subdirectory titled ‘Commands’.
Note that I’m assuming that updating of the UI isn’t tightly coupled to the object which is executing the command, otherwise I’d want the command to pass notification back to the calling object via a callback or event (which is the subject of the next article.) Rather, I’m imaging that the application is complex enough that multiple UI elements may need to be updated when the result comes back — in a case like that, UI update code doesn’t logically belong to the UI element that initiates the action. Although it’s possible to hardcode notification logic in the Command, it’s probably best to construct some kind of publish/subscribe notification system that passes updates to UI elements that are affected by changes to data items.
It’s also a bit simplistic to simply use an interface here: one of the great things about the Command pattern is that a Command (unlike an ordinary method) can be broken down into pieces which can be implemented or overridden in subclasses. I’ll often implement an abstract class like so:
public class AsyncCommand:ICommand { protected abstract void DoWork(); public Execute() { ... do some actions common to all commands ... DoWork(); } }
This works a bit like Aspect Oriented Programming and is good for logging, concurrency control and many other purposes. It’s also possible (and desirable) to wrap your callback methods, although (in mainstream languages) that does require you to write them a certain way — I’ll be talking about that in future posts.
Paul Houle on April 11th 2008 in Asynchronous Communications, Dot Net, GWT, Silverlight