One thing I haven’t discussed at all in this series is getting data from your data source in a Silverlight application. In my reference implementation (RI) I keep referring to in this series (see the overview post for a download link) I’m connecting to SharePoint both through the client side object model (CSOM) and the OData service.
Before I dive into calling services from your MVVM application I want to touch on something. One thing you might have encountered in building a Silverlight application is that when the application is in the design view either in Expression Blend or Visual Studio 2010, it is actually running just like it would be in the browser. This can be tricky if you’re developing offline or if you’re developing against a live service. Wouldn’t it be nice if there was a way to work with sample data? This way you could create your item templates visually without having to fret over live data or a live data connection.
Expression Blend aims to help you with this task with it’s ability to create sample data to bind to. That’s ok, but you don’t have much control over this. While it makes for a decent demo, whenever I tried to apply it I always found it lacking in some way. Then one day in late 2010 when Microsoft was running the Silverlight Fire Starter I watched a session by John Papa ( MVVM: Why and How? Tips and Patterns using MVVM and Service Patterns with Silverlight and WP7 ) that demonstrated a new way of working with data in a Silverlight app.
The approach he discusses is to use a service… or in the scope of this post a data service. This is an internal router in your app that figures out dynamically if you are in a designer or not. Then, depending on which one you’re in, it uses a different data provider. This way you can write code that generates your sample data and actually runs in design mode giving you complete control over your data. Yes, this does require a bit of extra work, but it isn’t that bad and the payoff is much better than the expense associated with it.
Let’s look at an example… take my RI project structure & I’ll explain each file from the bottom up (in the picture, the “data service” is the live service… the “design service” is what runs in the designers):
ServiceProviderBase.cs: This is the base class for the service provider. Its primary job is to create a new instance of the data service (design / live) depending on if the app is currently in a design tool or not. If it is in a design tool it creates an instance of the DesignServiceProvider class, otherwise an instance of the ServiceProvider class.
When the app calls ServiceProviderBase.Instance.ProductDataService it will get an instance of a class that implements IProductDataService which contains all data access methods that will call the live web service or create dummy data when the app is in a designer.
ServiceProvider.cs & DesignServiceProvider.cs: The two data service providers… one is for calls to the live web service (when actually running in a browser), the latter is used when the app is running in a designer tool. Think of these as more like factories that create the necessary service. It’s a bit of overkill in most apps… in my app I wanted to create two live services… one for REST and one for CSOM calls for SharePoint (to show the equivalent data access methods).
IProductDataService.cs: The interface that the data service providers implement. It contains all methods used by the app. In my RI these are
DesignProductDataService.cs: This is the data service that runs when the app is in a designer tool. It programmatically creates dummy data simulating a call to a real service. Here’s what the service looks like & what the categories worker does:
- ProductRestDataService.cs & ProductCsomDataService.cs: These are the live data services… one for the SharePoint OData service and one for the CSOM. They both do the same thing, they just use different endpoints. Here’s what the OData one looks like:
- One thing that might look a bit odd is the part here I’m converting what I get back from REST to a local model collection. The reason I do this is because you get very different objects back from CSOM or from REST. I wanted to standardize them on one model to make the rest of the application easier to understand… in a real app you’d pick one or the other but not both like I have. Remember, this is a RI which is used as a teaching sample.
OK, now you see all the pieces… how does it work? What I do is I pass an instance of the data service into the view model when I create it. So my view model looks a bit like this:
When the view model is created, which for me is in the ViewModelLocator as I’m using the MVVM Light Toolkit , I call the ServiceProviderBase and let it figure out if we’re in a design tool or running in “live” mode:
Now… anywhere in the view model, I just call methods on the data service and let the data service infrastructure I’ve created figure out where to get the data like so:
When my app is running in a designer, I get real data I can template and see how it looks, just like Expression Blend’s sample data, but I have infinite more control over the data. For instance I could create real relational collections! The picture below shows data created by the designer service.
The only thing you have to remember is that you need to compile your app to get it to see the design time data. This approach will allow you to do full templating of data in your application without the need for a live service and all the while having complete control over the sample data used in the application.