As Software Engineers we strive to build elegant solutions. We tend to layer our architecture so that our code is modular so that our code is testable and maintainable. With Silverlight this poses some particular challenges specifically when dealing with external services. All external calls from with Silverlight are asynchronous in order to prevent developers from locking up the UI thread waiting for the response. How do we build our applications to conform to this while keeping us from tightly coupling our applications to the services we consume.
In this post I will document an approach that I have used a couple of times that allows me to layer my Silverlight application in the way I would any other application. That is the first trick to developing in Silverlight. Treat the Silverlight part of the application as if it were is its own application, because it is! This holds true whether you are using RIA Services or getting your data from an external web service. By treating it as its own application you tend to bring in accepted coding practices but as I stated before there are some challenges.
For this blog I am going to use a project that I just started and will be working in my spare time. I am building a File downloader to download content from Microsoft’s Mix11 Conference. This little project was inspired by a project Mike Taulty did for last year’s PDC. I know that there are easier ways to download the video content from the conference. Scott Hanselmen documents one such way by using the RSS feeds from Channel 9. This is more of an exercise to build an application that consumes an OData feed while at the same time maintaining an elegant solution.
Here is my initial layer diagram that I am working form:
These are the layers that I have come up with and will be working with through out this project. I will be covering the details and interesting aspects of each layer in the following sections.
I choose to use M-V-VM when I develop with Silverlight. This pattern allows for separation of the UI markup from the functionality. There are many frameworks that help out when working with MVVM. The one I like to use the most is MVVMLight. This is a nice light weight framework that contains a bunch of templates, some base classes and a messaging service. Laurent Bugnion is even adding a light IoC container in the next version. There are other frameworks that perform similar functionality and are just as good (Prism for one). I started using MVVMLight a few years ago and haven’t turned back since.
The next key to an elegant solution is to use a ViewModelLocator. There are a few schools of thought when it comes to binding ViewModels to Views. Some new them up in the constructor of the Views. The problem with this is that there is no design time feed back using this method. Others like to declare the binding in Xaml. This is similar to how I do it except that I bind to a property in my ViewModelLocator. With a ViewModelLocator you can control the lifetime of the ViewModel (new instance for each load or created once for the lifetime of the application).
Here is my ViewModelLocator:
Here you can see that I am using my locator class to inject a dependency into my ViewModel (I may changes this in the future to use the Simple IoC class from the MVVMLight framework). I create an entry in a Resource Dictionary for my locator class. So binding the ViewModel to the View is as simple as this:
In my ViewModelLocator you should notice a class called ServiceProviderBase. You may be asking yourself what purpose does this serve. I will tell you. As you recall from our layer diagram our data access services live in another project. This class serves a factory for serving up our services. In order to have design time data a DesignServiceProvider is created. Let’s take a look at the base class:
As you can see it is implemented a Singleton and which instance to serve up is determined in the CreateInstance method. This method determines if it is design time or run time and serves up the proper provider. That rounds out my Presentation Layer except for some Resources and Value Converters (the other things that make the UI elegant).
You can’t have MVVM with a Model. If you did you would VVM and that just does not look balanced! In this project I am not doing anything fancy. I did decide to create a model that is separate from the model that is generated from the service proxy. This will allow me to switch out the service layer implementation (say when the next conference happens) with little impact to my presentation layer. I handle the mapping in the service layer. That concludes the model layer, I will now return you to your regularly scheduled program…..I told you not too exciting.
When I am developing Silverlight application, I find that there are some classes I can’t live without. These classes are needed in all the layers so I like to pull them out to a separate project that can be referenced throughout the application. Someday I may even create my own open source collection of these things. One of the biggest short comings of the Silverlight framework is a means to convert an IEnumerable into an ObservableCollection. ObservableCollection’s are used to bind collections to the ItemsSource property of ItemsControls. The observable part is what allows for updates to be delivered to the UI when something changes. So I implement this as an extension method in my common project. This is the kind of stuff that I like to put in.
One of the key things needed to separate out the services from the rest of the application is to have a means handle the asynchronous nature of service calls, especially when they are happening in a different dll. How does that presentation layer know when the service call they made is finished? I have seen a few different ways to handle this including creating events in my service layer that the ViewModels cans subscribe to. This is kind of like recreating the functionality in the proxy. This approach can complicate things when it comes to unit testing. The approach I like to take is to build out an object that contains a callback action. This approach is similar to the approached outlined by Ben Day in his post Silverlight Asynchronous WCF Calls Without Ruining Your Architecture. Here is my implementation of his ReturnResult object:
The premise is that this object will be passed into all service calls. When the service returns the Notify method is called with either the results or and exception. The ViewModel can then handle this. This brings us to our Service Layer.
The Serivce Layer
This is the layer that is responsible for ferrying the data between the source and the Presentation Layer. The source can be anything from an RSS feed to a SOAP Service or in our case an OData feed. Here I am abstracting out the how the data is retrieved allowing the Presentation Layer to concentrate on presentation. I start out by creating a ServiceBase that is responsible for instantiating the proxy. Here is my ServiceBase for the Mix11 OData feed:
I then create a design time service that returns design data and I create an actual runtime service. In Silverlight all service calls return void. The magic happens in the callback method. How do I get access to my ResultAction<T> object in the callback method? With a proxy created from a web service all the service method calls have an overload that takes an object that is available in the callback. all you have to do is cast it as the ReturnAction<T> and be on your way. I could not find such a thing when dealing with the DataServiceCollection<T> object used to pass queries to the OData service. So I created my own caller that inherits from DataServiceCollection<T> and has a property to hold any state that must persist after the call returns. Here is my caller:
And here is an example of this class in action pre call:
and post call:
This also shows the ReturnAction<T> class in action. All my services implement interfaces that are used by the Presentation Layer in the ServiceProviders. The Service Layer allows for many different data sources. Adding/subtracting sources or even changing source will not have any affect on the Presentation Layer as long as they adhere to the contracts set forth in the interfaces.
This is a good place to stop for this post. In this post I have laid out a layered architecture that can help developers build elegant Silverlight solutions. I have addressed some of the pitfalls associated with Silverlight development and proposed solutions to those pitfalls that have worked for me. As I get further along in my quest for building this downloader I will write further post that other may find useful.