WCF RIA Services - Hands On Lab
At the keynote for the Silverlight 4 Launch alongside Scott Guthrie I demonstrated
The application I built is an online book store to rival the big boys … OK, well, maybe not the big boys but you get the idea. As promised I am elaborating on the presentation and breaking down the steps to create the application here.
I included the starter solution and the completed solution for this presentation so you can try this out for yourself or simply run the completed solution if that interests you more. In this post I will go through the steps to create the application so you can try this as well.
Here is the completed application that I will show how to build. You can select a book category and the books for that category will appear in the book list in the middle. You can sort by title or author or you can filter the book list by title or author. If you log into the application (as RIA Services integrates well with ASP.NET authentication) I show how to set up permissions to edit the book information too. OK, so this was a stretch as you really don’t want to allow book information to be edited by buyers, but work with me on this :-)
Where Do We Start?
Let’s start by examining what is already in the project. Open the starter project and notice that there are already a Silverlight project and a Web project created.
So the lower tier architecture contains a SQL Server database which stores the book information and an Entity Framework model which maps to that SQL Server database. RIA Services will operate on the Entity Framework model for both retrieving and modifying data using LINQ to Entities in this application.
Create the Domain Service
To create the domain service you then add a new Domain Service Class to the Web project and name it BookClubService.cs.
Configure the Domain Service
When you configure the domain service RIA Services can see all of the entities that the Entity Framework model exposes. You can select which entities you want the domain service to
I will also check the box to “Generate associated classes for metadata”. This creates a BookClubService.metadata.cs class. This is where you can define validation and business rules that you want to share between the server and the client. The code in this class will be copied to the Silverlight client when the application is compiled.
</f ont>
Returning Object Graphs
When we get the book of the day we want to get the BookOfDay entity and its child entity, Book. By default when asking for a BookOfDay entity from a domain service it will only return BookOfDay entities, and no child entities. Since this is not what we want we can decorate the Book property of the BookOfDayMetadata class with the Include attribute. We’ll also have to configure the domain service method for getting the BookOfDay entities to include the Book entities too … but we’ll do that in the next step.
1: internal sealed class BookOfDayMetadata
2: {
3: // Metadata classes are not meant to be instantiated.
4: private BookOfDayMetadata()
5: {
6: }
7: //Include the book for the object graph
8: [Include]
9: public Book Book { get; set; }
10: public int BookID { get; set; }
11: public DateTime Day { get; set; }
12: }
Customize the Domain Service Methods
The BookClubService class (generated in step 3) contains a series of methods that will be exposed to the Silverlight client. You should see a series of methods to retrieves the entities and a few methods to insert, update and delete Book entities. While this code is generated we can modify the code without risk of it being overwritten. (The domain service generated class is not one that is regenerated on the fly.) So we can edit the GetBooks method to return the books in sequence by title.
1: public IQueryable<Book> GetBooks()
2: {
3: return this.ObjectContext.Books.OrderBy(b => b.Title);
4: }
Then change the GetCategories method to order the Category entities by the CategoryName.
1: public IQueryable<Category> GetCategories()
2: {
3: return this.ObjectContext.Categories.OrderBy(c => c.CategoryName);
4: }
Now change the GetBookOfDays method to include the Book entity and return the most recent BookOfDay entity and its Book.
1: public IQueryable<BookOfDay> GetBookOfDays()
2: {
3: return this.ObjectContext.BookOfDays.Include("Book").OrderByDescending
4: (b => b.Day).Take(1);
5: }
Build the application and the services will be exposed, the models shared, and the metadata shared to the Silverlight client.
Configure the Data Sources to use ListBox Controls
Now let’s go to the Silverlight client in Visual Studio 2010. Open the Home.xaml View in the designer. Styles have already been applied to the View by my Designer, which yields a nice l
We don’t want a DataGrid, though. So lets change the type of control to a ListBox. Click the arrow to the right of the Book in the Data Source window and select Customize. When the Customize Control Binding dialog appears scroll to ListBox, select it, and click the Set Default button. This tells the Data Sources window that we want the ListBox to be the default option when dragging and dropping to the design surface.
Now, go back to the Data Sources window and the Book should now show a different icon that represents the ListBox.
Drag the Data Sources to the Design Surface
Drag the Category from the Data Source window to the rectangular Grid panel below the Book Categories title. Then right click the ListBox and choose Reset Layout | All. This makes the ListBox consume all of the space inside of the Grid.
Drag the BookOfDay to the BookOfDay Grid and reset the layout to “all”. Then drag the Book to the Book Grid and reset the layout to “all”.
The ListBox controls are now created, aligned, and bound to the newly created DDS controls. The Silverlight client is also now wired up to retrieve the data for these bindings from the domain service class we created in the previous steps.
Now drag the Book from the Data Sources window onto the DataPager control. This binds the DataPager to the same DDS that the Book ListBox is bound to, thus enabling paging.
Apply the DataTemplates
Now it is time to apply the DataTemplates for the 3 ListBox controls. These DataTemplates were created in advance by our designer as resources and are quite simple. For example, the DataTemplate for Book looks like this:
1: <DataTemplate x:Key="BookItemTemplate">
2: <StackPanel Orientation="Horizontal">
3: <TextBlock Text="{Binding Title}" Margin="8,0"/>
4: <TextBlock Text="(by "/>
5: <TextBlock Text="{Binding Author}"/>
6: <TextBlock Text=")"/>
7: </StackPanel>
8: </DataTemplate>
We can apply the DataTemplates to the ListBoxes using the new Visual Studio 2010 tooling for
Apply Filters
We want to filer the books by the selected category and by the title or author (whichever is selected in the combobox and value typed into the TextBox above the Book’s ListBox). We can do this through the Visual Studio 2010 tooling by first going to the Document Outline window and selecting the bookDomainDataSource. Open the Properties window, find the FilterDescriptors property, and click the button (the one with the 3 dots).
When the Collection Editor for the FilterDescriptors appears click the Add button to add a new filter. This filter will make sure the books are filtered by the selected category. Set the PropertyPath to the string “CategoryID” (without quotes). Then click the square next to the Value property, click the Apply Data Binding options, and the binding dialog appears. For the Source select the ElementName binding and the categorylistBox, as shown below.
Now for the Path select the SelectedItem property as shown below. We just created a filter so only books for the selected category will appear.
Now we need to create a filter by the partial name entered for the author or title. Add another filter descriptor and set the Operator to Contains (we want to do partial matching of the title or author). Bind the PropertyPath to the cboSort combobox’s SelectedItem.Content property, as shown below.
Then bind the TextBox named txtFilter and to its Text property, as shown below.
These steps created the filters but there are 2 additional steps we need to take. First, we need to go to the XAML of the filter for the category and set the Path to SelectedItem.CategoryID. (The tooling does not support the free form entry of the CategoryID in the filter dialog.) Next, I want the FallBackValue for the same filter to be set to 1. This way if a category is not selected the filter will be applied to the first category. When you are done, your XAML for the filters should look like this:
1: <riaControls:DomainDataSource.FilterDescriptors>
2: <riaControls:FilterDescriptor Operator="IsEqualTo" PropertyPath="CategoryID" Value="{Binding ElementName=categoryListBox, Path=SelectedItem.CategoryID, FallbackValue=1}" />
3: <riaControls:FilterDescriptor Operator="Contains" PropertyPath="{Binding Path=SelectedItem.Content, ElementName=cboSort}" Value="{Binding ElementName=txtFilter, Path=Text}" />
4: </riaControls:DomainDataSource.FilterDescriptors>
Apply Sorting
The next step is to apply the sorting. Select the bookDomainDataSource from the Document Outline window, go to the Properties window, and find the Sort Descriptors property. Click the button and when the sort dialog opens, add a new SortDescriptor. Here we want to sort by the selected value in the cboSort combobox. Click the PropertyPath’s binding icon and select the Apply Data Binding option. Set the Source to cboSort and set the Path to SelectedItem.Content.
Your XAML for the SortDescriptor should look like this:
1: <riaControls:DomainDataSource.SortDescriptors>
2: <riaControls:SortDescriptor PropertyPath="{Binding Path=SelectedItem.Content, ElementName=cboSort}" />
3: </riaControls:DomainDataSource.SortDescriptors>
Bind the Book Control
The next step is to bind the selected book (from the ListBox) to the BookControl. The BookControl is already created (in a separate XAML file in my project). It contains the layout to display and edit the book’s property values. All it needs is a book for its DataContext to bind to.
Select the BookControl, go to the Properties window, and find the DataContext property. Click the binding button next to the DataContext property and choose the Apply Data Binding option. use the binding picker to bind to the ElementName of bookListBox and the Path of SelectedItem. Now our BookControl is bound to the selected book.
Bind the Submit Button
We can support saving changes made by the user by binding the Submit button control to the bookDomainDataSource control’s SubmitChanges method. Select the btnSubmit control, go to the properties window, and find the Command property. Click the binding button next to the property and choose the Apply Data Binding option. Set the Source to the bookDomainDataSource and set the Path to the SubmitChangesCommand. (This command is part of the DDS you created when you dragged the Book from the Data Sources window onto the design surface.)
Now it is time to run the application. Click the login link and register a username and a password.You will need this information to log into the application so you can edit the book details.
This will take advantage of the authentication that is set up by default by WCF RIA Services. This includes an auth database, services to log in and register users, log in controls, and wiring up the services to the Silverlight client.
Once you log in you can use the application to:
- choose different categories and watch the books get filtered
- change the sorting for the books
- filter the books by partial name of the author or title
- select a book and view the book details in the book control
- page through the books
- edit details of a book
- submit the changes for the book
You might notice when you edit the book details that some fields are in bold. These fields have validation attributes applied to them for required fields. If you remove the text from the ASIN TextBox the control will be highlighted in red. This means the validation condition not been met. If you hover over the upper right corner of the TextBox on the red triangle you will see a message that explains the problem.
This application stepped you through creating the fictitious Online Book Shelf application using RIA Services. if you have 10 minutes, you can watch me follow these steps (rather quickly with some variations) from the keynote from the Silverlight 4 launch using the following link. I begin 28 minutes in and spend about 9 1/2 minutes on the demo.
You can download the source for the completed version of the application or the starter from these links:
NOTE: After you download the zip files, make sure you unblock them. Also, I recommend cleaning the solution before you start working through the steps.
Several people contributed heavily to this keynote demo and application including Deepesh Mohnani, Jeff Handley, Dinesh Kulkarni, and Nikhil Kothari. Thank you all for your huge contributions!
Now for something Different …
If you made it this far in the post, you can even watch a pre-keynote warmup (tongue in cheek) from me and Ward Bell.