Prism for Silverlight 2: Taking ‘Hello World’ to a Whole New Level
The World’s Most Over-engineered “Hello World” Demo
I wanted to build a demo/guidance application for Silverlight that merges everything I want to accomplish in a Silverlight 2 application. These were my goals:
- WCF integration
- Design-time data binding
- Independent, decoupled modules
- Commanding support
I chose to use the Composite Application Library for WCF/Silverlight (aka Prism 2) since it came out of the box with commanding support and a framework for pluggable modules. Prism 2 was developed by Microsoft’s Patterns and Practices (PnP) group.
I’ve posted a copy of my solution for anyone who’s interested in looking it over and maybe a more simple example than the Reference Implementation (RI) provided by the PnP team. The biggest part of this exercise for me was the integration of WCF with Prism. The RI provided with the Prism documentation uses a local XML file as a data source. For me this was disappointing. I had been hoping for a more complete RI since Silverlight really isn’t worth anything as a LOB platform without integration with web services.
Now that I’ve finished, I’d like to share both my sample and what I’ve learned.
What This Post Is Not
This post is not a detailed document on Silverlight, WCF, Prism or DI/IoC. These are all used and are relevant to the discussion, but in the interest of time these are all beyond the scope of this post. I have tried to provide helpful links to information along the way, but for more information on related technologies beyond the scope of this post consult the links I have provided as well as google.
I tried to model the solution structure to mirror what would be realistic of an enterprise-level application. I wanted minimal project dependencies and a modular design. Here’s a description of the structure and why.
Implicit in my goals was that I did not want my modules referencing each other. So I created a Silverlight Class Library project which contains my interfaces, base and utility classes named HelloWorld.Interfaces. This is the only project referenced by the other class library projects.
The only project which references the modules is the Silverlight Application Project named HelloWorld.Silverlight. At this point I am not dynamically loading assemblies since I don’t actually need it yet. I may add it down the road, but for now my needs are met.
Client/Server Shared Files
Also, I wanted to be able to use the same code base on the server as well as the client. I didn’t want to have to copy/paste code for interfaces and my data model between layers. So for objects and interfaces which are used by both the client and the server I created the class files in the server projects (Windows Class Library and ASP.NET Web Application) and then added the same files to the Silverlight projects via Add Existing File… –> Add as link…
There really isn’t much to say about the service itself. For my purposes the interface is the important part:
By defining a second interface to represent the service contract as an asynchronous pattern the client can bind directly to the asynchronous interface without having to define a wrapper class on the client side.
For me this was the biggest part of this exercise. Originally, I used the “Add Service Reference…” wizard to add a reference to my service. However, this had several shortcomings I wasn’t happy about which all boiled down to one deal-breaker for me: any module using the interface would require a reference to my services project.
1) I couldn’t control the namespace used. Yes, it asks me for the namespace, but that is appended to the default namespace of the project where the service client is added. I’d rather have complete control over the namespace.
2) The wizard will reuse the model classes in my other projects if I ask it to, this is a plus. However, it won’t reuse my interfaces. The reason this is a problem is that I am tied to the client that is generated, so can’t just reference my interfaces project I have to either place my service client in my interfaces project or reference the service project from each other project.
3) The asynchronous event model used is simple and easy to use, but it’s tied to concrete EventArgs implementations. This in and of itself is not the problem. My problem with this is that again, I am tied to this one file and its location in my solution. I’m required to have references to it across my solution and so I am really only pretending to program to a loosely coupled set of interfaces. I’m really still tied to a concrete implementation. This may seem silly to some, because I could still use the interfaces and if I really needed to replace the implementation I could. But it just felt wrong.
I understand the constraints behind the output from creating a service reference, but there was just so much maintenance work involved in using it in a loosely-coupled way that once I found an alternative that I dumped the service client implementation.
So I was grateful to find this post by Ayende Rahien. All that is required is that I create a link to the interfaces defined in my Windows Class Library project (Silverlight requires this, WPF could just reference the Windows Class Library directly). Then to create a proxy for use on my client I just do this:
Nice, clean and no maintenance. I don’t even have to regenerate the proxy when the interface changes.
However, there is a tradeoff.
The nice thing you don’t have to worry about when using the service client proxy is threading. I haven’t figured out why yet, but something to do with the way the events are handled by the generated proxy means you can just register for the XXXCompleted event then call the XXXAsync method and directly update your UI from the XXXCompleted event handler. This is called the Asynchronous Event Model. However, using ChannelFactory<T> means you’re not using events, you’re using callbacks – what I’ll call the Standard Asynchronous Model (aka BeginXXX and EndXXX).
This is where Dispatcher comes in. Dispatcher is a class located in System.Windows.Threading. Without getting into details, Xaml based apps (Silverlight and WPF) are single-threaded. But Silverlight requires you to execute blocking calls asynchronously. So when your asynchronous method completes you’re on a different thread. Dispatcher allows you to execute a System.Delegate or System.Action back on the UI Thread. This way you can make updates to your UI based on the result of your service call.
Like I said, if you’re using the service reference proxy this is handled for you. Otherwise you need to do this on your own. So here’s what I’ve done:
This is so I can create an adapter for Dispatcher to be used when the application is running, then I can also write tests using a MockDispatcher which means my tests can then execute on a single thread because my MockDispatcher would be single threaded. This wasn’t my idea, I was just able to find it thanks to StackOverflow.com.
Here’s my implementation of IDispatcher:
Now that w'e’re looking at this, you may notice something a bit hackish. You’ll notice that my ctor has a Boolean parameter named isHtmlEnabled. And you’re asking why doesn’t this guy just reference System.Windows.Browser.HtmlPage.IsEnabled? Well, origionally I did. But inside this class (project?) the value returned was always False. Since my dispatcher is being used as a Singleton I just get the value of HtmlPage.IsEnabled during the StartUp event of App and pass it into my Dispatcher. Since this was easy to do and doesn’t cause me any problems I’m fine with this. If you actually know why this happens and have a suggestion, please let me know. But I posted a question about this on Silverlight.net forums and didn’t get an answer, so this is what I’ve got.
Now, when the app is actually running I can safely update the UI thread. When the app isn’t running (Test run or Design mode) I can directly execute the passed in Action or Delegate. Here’s how to use it:
Design-time Data Binding
This was an important issue for me for a couple of reasons:
- I suck at UI design and can use every bit of help I can get
- I’m working with a Flash developer and I’d like to make things as simple as possible to remove as many obstacles as possible.
- I want to know my bindings work without having to compile and load up the web browser.
I originally saw Jonas Follesoe demonstrate this last summer in a TechEd 2008 webcast. He created a ServiceLocator which used Ninject to load up a mock service provider during design time. By adding the ServiceLocator as a static global resource to App.xaml the Silverlight designer initializes ServiceLocator and then displays the data in your preview window (NOTE: this doesn’t work in the VS 2008 preview window just in Blend, but from what I read about VS 2010 it might work there).
The difference between Jonas’ DiveLog application is that my views aren’t in the same project as App.xaml, so I need to add a reference to ServiceLocator as a local resource in my view file. A small difference, but important to note nonetheless.
Also, I need to update the Container property during my module’s Initialize method so I can maintain a reference to my runtime UnityContainer.
I’ve really learned a lot from this exercise and I hope it helps others. I know I’ve still got quite a bit to learn but I figure this is a good starting point for anyone wanting to take advantage of Prism and it goes a bit further than the PnP RI. I welcome any comments on improvements or questions. Over the summer I will be putting this all to a real-world test and I will continue to provide updates on what I’ve learned.