WCF Ria Services For Real

In my previous post I discussed creating the database and tables for the Silverlight HVP configuration data. All that was great, and worked just dandy until it was time to get the data from the database server to the application running on the client.

“But,” I thought, “How hard can it be?” I’ve done a few mini-tutorials… should be straight-forward… And it was… sorta.

Getting Going

The steps are pretty straight forward:

Create an entity data model that corresponds to the tables

Create a Domain Service to handle transport and creation of classes

Modify the queries to select the data you want

One of the strengths of WCF RIA Services is also one of its most confusing aspects: there are many good designs to accomplish the same thing. I’m a big believer in doing things in the most intuitive and obvious way and then looking to optimize or improve if and when it proves to be needed.

In this case, I had chosen to simplify the persistence of the various fields in my business objects as simple types in the database. For example, here is the Topics class and its base class:

The Topic class and Listable class are declared in Topic.cs and Listable.cs respectively

Notice that Image is of type ImageSource and TopicOffset of type Timespan. Here is how they are declared in the database:

Each record has a unique ID, and Topic’s MyListableID is a foreign key into Listable, linking the two into, effectively, a single object.

It is an interesting aside that normalizing the Topics, Items and Links tables called for factoring out the same fields into a new table as were factored out into a base class when creating the types. In many ways this makes sense, as in both normalization and refactoring, the goal is to eliminate duplication.

Returning to my original point, however, while the Listable type stores its Image field as an ImageSource, the ImageSource field in the database is a string. Similarly, while the Topic type stores the Offset as a TimeSpan, the value is stored in the database as an integer (the number of seconds).

There are numerous ways to resolve these differences, among them:

Store the values in the database as they are stored in the objects

Create conversions or a converter class

Retrieve objects that represent the database fields, and convert the values when initializing the ViewModel objects

If I were starting from scratch, and if I knew that the only way these values would ever be stored is in the database, I could make a good argument for the idea of storing the values in the database as the same types used in the objects. That is not how this evolved however, and, in fact, if/when we decide to persist the objects to Xaml before sending them to the db, any work that was done to create an isomorphic mapping to the database would be wasted.

Thus, again, I let the design evolve organically, even if that doesn’t leave me, from time to time, with what looks like the optimal (or at least text-book) way of doing things.

Creating the Entity Data Model

The mechanics of creating the Entity Data Model couldn’t be much easier. Step 1 is to Add a New Item to the SilverlightHVP.Web project, of type ADO.NET Entity Data Model (found in the Data Templates).

When you click Add, Visual Studio will ask for your source, in this case you will pick Database. It will then allow you to create a Connection String to the configuration database.

Once the connection is established, you pick the tables and views you want in the Entity Data Model, and hey! Presto! Visual Studio creates the model for you.

The relationships in the Entity Data Model map to the relationships in the database. You are free to modify the entities, but it is simpler to let Visual Studio do the heavy lifting.

It is very important to build the SilverlightHVP.Web project at this point, before going further.

With the project built, you just click on Add New Item to SilverlighHVP.Web once more, and this time click on the Web template, and then on Domain Service Class, and give your new service a name (e.g., HVPConfigRiaDomainService)

This brings up the Add New Domain Service Class dialog, in which you pick the entities (from the Entity Data Model) you wish to access through your WCF Ria Service. Since I want access to them all, but do not need to edit them, I’ll check all the Entities in the left column.

Hiding, inconspicuously in the lower left corner is an important CheckBox: Generate associated class for metadata. Click that CheckBox and then click OK.

Visual Studio will place you in the editor, inside the HVPConfigRiaDomainService.cs file. Here you will see the code that was generated to retrieve data from your tables.

The generated code can be modified to select the records you want, and to order the results as well, as shown in the next code listing.

Retrieving Items, Topics and Links

When the program begins we create a situation identical to that of when the user clicks on a link: we need to retrieve a new Set of items. Remember that a Set consists of one or more Items (e.g., videos) and each Item has zero or more Topics and zero or more Links. Each topic is tied to an offset in a given video, each Link is tied to a Set.

The State constructor takes an integer parameter indicating which Set to obtain (at the moment, the shell creates the State object and passes in the value 0).

The heart of this method is within the try block, where we ask the Context object to load the GetItemsViewQuery we modified above. The object returned from a call to Load is of type LoadOperation<ItemsView> which we can use to set an event handler on the completion of the asynchronous Load.

The penultimate line of code shows the CurrentItem property of State being set within the Item object that is held by the ItemHOlder located at the currentItemHolderOffset offset. That value is set to 0 initially, and updated as the current item changes.

Notice that the value is set by way of the property. The setter for the CurrentItem property does a bit of housekeeping,

Specifically, the setter updates the CurrentItemHOlderOffset value and, even more important, calls the GetTopicsAndLinksForItem method, passing in the ItemID.

The Items (and the links) are then independently and asynchronously loaded from the database, much as the Item was.

Lazy Loading

This design allows for the topics and links of an item to be loaded to the client only as need and asynchronously, providing a more responsive UI that is not bogged down waiting for any of the list boxes to fill. Since the video is streamed in small bursts whose quality (size) is set in response to current bandwidth, the entire application should appear “snappy” even though three queries are returning data for the configuration.

I’m very happy to report that we are on track for version 1 to be ready in time for Mix, and we are already selecting the most important new features for versions 1.1 and 2.0. For more information on this project, please take a look at the CodePlex site.

About Jesse Liberty

Jesse Liberty is an independent consultant and programmer with three decades of experience writing and delivering software projects. He is the author of 2 dozen books and multiple Pluralsight courses, and has been a Senior Technical Evangelist for Microsoft, a Distinguished Software Engineer for AT&T, a VP for Information Services for Citibank and a Software Architect for PBS. He is a Xamarin Certified Mobile Developer and a Xamarin MVP, Microsoft MVP and Telerik MVP.

Could you post a tutorial of Pagination and and usage of FilterDescriptors with datagrid in client side. I’m asking this specially because, it is said that when we have FilterDescriptprs or pagination it will propagate to the final SQL query, not we fetch all data from database but then apply filters, is it true?

for example in your code above think following method in DomainService

public IQueryable GetItems() { return this.ObjectContext.Items; }

So if we use this in client side with a datagrid and if we apply filterdescriptors, is that final SQL to the database contains those in where clause or is it fetching all and filtering done at the DomainService?

Which doesn't deal with database at all and if we apply FilterDescriptor for CategoryId still it works, so my question is how to we capture these filterDescriptors at DomainService level and optimize final SQL query by using them if currently filtering done after fetching all records from the database.

Hi Jesse, moving from the old blog to the new, how do I add you to the Feeds in Internet Explorer 8? Clicking “RSS” at the top of the page proposes different services but I cannot find how to directly add your blog RSS to IE.