RIA Services – Displaying data with Silverlight 4 Beta & Visual Studio 2010 Beta 2

NET RIA Services is a set of tools and libraries that make the life of a RIA (Rich Internet Application) developer much easier. Basically if you are writing a Silverlight application that will ever need to talk to your server, then .NET RIA Services will prove to be very useful.

The beauty of this programming model is that you get to work with high level entities, instead of low level relational database constructs. If you don't know why entities are interesting, see a previous blog post:
https://blogs.msdn.com/brunoterkaly/archive/2010/01/25/ado-net-entity-framework-and-net-4-how-to-use-visual-studio-2010-modeling-tools-to-build-a-database.aspx

These entities are easily queried using LINQ. In addition, your typical business application will need to be able to create, update, and delete data. All these abilities are built into RIA Services.

Other great abilities include the ability to maintain local state in Silverlight, manage dirty entities, perform batch updates, perform transactions, and even access authentication, authorization, and profiles.

All these great things happen with http, whose often difficult programming model, has been abstracted away.

image

My previous blog post built the project you see below. Make sure you quickly go through that post so the rest of this makes sense to you.

image

 

The Northwind database – where to download

Do a search on Bing for “Northwind and pubs Sample Databases for SQL Server 2000” and you should find this link:

https://www.microsoft.com/downloads/details.aspx?FamilyID=06616212-0356-46a0-8da2-eebc53a68034&displaylang=en

image

 

image

The Northwind database – building the database

The key file is instnwnd.sql.

image

This is only a fraction of the .sql code.

Code Snippet

  1. SET NOCOUNT ON
  2. GO
  3.  
  4. USE master
  5. GO
  6. if exists (select * from sysdatabases where name='Northwind')
  7.         drop database Northwind
  8. go
  9.  
  10. DECLARE @device_directory NVARCHAR(520)
  11. SELECT @device_directory = SUBSTRING(filename, 1, CHARINDEX(N'master.mdf', LOWER(filename)) - 1)
  12. FROM master.dbo.sysaltfiles WHERE dbid = 1 AND fileid = 1
  13.  
  14. EXECUTE (N'CREATE DATABASE Northwind
  15.   ON PRIMARY (NAME = N''Northwind'', FILENAME = N''' + @device_directory + N'northwnd.mdf'')
  16.   LOG ON (NAME = N''Northwind_log'', FILENAME = N''' + @device_directory + N'northwnd.ldf'')')
  17. go
  18.  
  19. exec sp_dboption 'Northwind','trunc. log on chkpt.','true'
  20. exec sp_dboption 'Northwind','select into/bulkcopy','true'
  21. GO
  22.  
  23. set quoted_identifier on
  24. GO
  25.  
  26. /* Set DATEFORMAT so that the date strings are interpreted correctly regardless of
  27.    the default DATEFORMAT on the server.
  28. */
  29. SET DATEFORMAT mdy
  30. GO
  31. use "Northwind"
  32. go
  33. if exists (select * from sysobjects where id = object_id('dbo.Employee Sales by Country') and sysstat & 0xf = 4)
  34.     drop procedure "dbo"."Employee Sales by Country"
  35. GO
  36. if exists (select * from sysobjects where id = object_id('dbo.Sales by Year') and sysstat & 0xf = 4)
  37.     drop procedure "dbo"."Sales by Year"
  38. GO
  39. if exists (select * from sysobjects where id = object_id('dbo.Ten Most Expensive Products') and sysstat & 0xf = 4)
  40.     drop procedure "dbo"."Ten Most Expensive Products"
  41. GO

 

Start Microsoft SQL Server Management Studio and choose, “File, Open, File”

image

Open instnwnd.sql  and go to SQL Server Management Studio and hit the “f5” key or go to the menu and choose “Query, Execute.”

image

Notice that we have a Northwind database. We will work with some of the tables here in our Silverlight RIA Services project.

image

image

The Northwind database – adding and ADO.NET Entity Model

image

We need to add a third project. It will be used to contain our data model. In reality, we will use it to contain an ADO.NET Entity Model.

Add a “New Item” to our “HelloWorld.Web” project.

image

Silverlight will use an ADO.NET Entity Data Model to query the data store.

image

We will generate our entity model using the previously created Northwind database.

image

Select the Northwind database that your created in previous steps:

image

Make sure to select 3 tables:

  • Customer
  • Orders
  • Order Details

image

image 

The finished entity model. Our Silverlight RIA Services Application is ready to move forward. In a moment, we are going to add a “Domain Service.”

image

In the HelloWorld.Web project add a “New Item to the “Services” folder.

 image

Perform the following:

  • Choose Domain Service Class
  • Give a name of NorthWindDomainService 

image

Note that we checked a total of 8 checkboxes

  • 3 to select the entities (Customer, Order, Order_Detail)
  • 3 to enable editing (we want to do basic CRUD – Create, Read, Update, Delete)
  • 1 to enable client access (exposing the data to client browsers)
  • 1 to generate data for associated metadata (used in validation later)

image

image

What does the Domain Service do?  It is the heart of a WCF RIA Services application. It is a beautiful thing  because it manages serializing our objects for both the server side and client side. We only write our code once and both client and server projects in our solution have our data model available and easily programmable.

Think of it as the server side of a communication with a remote browser based client. If you look at the Silverlight project, you will note that some code has been generated for us. Let’s learn some of the deeper details.

image

The Domain Context is what the client works with. It is a perfect mirror of the Domain Service, which runs on the Server.

First rebuild your solution (this will generate code)

image

Next, click on “Show All Files”

image

By looking at the generated code you can learn more about what is taking place. Here is the interesting part. When you compile, the code gets copied to the Silverlight Project. In other words, your “Domain Service” becomes your “Domain Context” without having you write any code. When you compile, that is when the Domain Service “morphs” itself into the Domain Context on the client.

 

This is nothing more than traditional proxy code. You should not edit this code because it will be re-generated once you compile.

image

 

The code that is reflected is placed in the Domain Context.

Here is a list of classes that gets generated for client consumption. Remember the goal – to get a DomainContext, which is a stateful client side representation of a DomainService, providing access to all the functionality of the DomainService.

public sealed partial class WebContext : WebContextBase
  - Provides a context to make services and other resources available for the application.

public sealed partial class AuthenticationContext : global::System.Windows.Ria.ApplicationServices.AuthenticationDomainContextBase
  - A context used for authentication
public sealed partial class User : Entity, global::System.Security.Principal.IIdentity, global::System.Security.Principal.IPrincipal
  - A user representing the request for data

**Key part**
public sealed partial class UserRegistrationContext : DomainContext
public sealed partial class NorthWindDomainContext : DomainContext

  A DomainContext is a stateful client side representation of a DomainService, providing access to all the functionality of the DomainService.

internal sealed class AuthenticationContextEntityContainer : EntityContainer
internal sealed class UserRegistrationContextEntityContainer : EntityContainer
internal sealed class NorthWindDomainContextEntityContainer : EntityContainer

  Represents a cache of entities in the form of a collection of EntitySets.

public sealed partial class Customer : Entity
public sealed partial class Order : Entity
public sealed partial class Order_Detail : Entity
public sealed partial class RegistrationData : Entity

  Our entities being consumed by Silverlight runtime at the client browser

Enhancing NorthWindDomainService.cs

  • When you add a method to a domain service, it gets automatically reflected back to the the Silverlight “HelloWorld” project.
  • You need to recompile after adding a method to NorthWindDomainService.cs

image

You may wish to add custom methods to the domain service. For example, in the code below you can see that Intellisense is a big help.

Lets add a method that returns customers from the United Kingdom.

image

When I compile my project, this custom method in my Domain Service will get reflected back to the client Silverlight project.

You will add this custom method before re-compiling.

image

Code Snippet

  1. public IQueryable<Customer> GetCustomersInUK()
  2. {
  3.     return this.ObjectContext.Customers.Where(e => (e.Country == "OK"));
  4. }

image

image

Let’s compile to make sure there are no mistakes.

Code Snippet

  1. ------ Rebuild All started: Project: HelloWorld.Web, Configuration: Debug Any CPU ------
  2.   HelloWorld.Web -> c:\devprojects\Silverlight\HelloWorld\HelloWorld.Web\bin\HelloWorld.Web.dll
  3. ------ Rebuild All started: Project: HelloWorld, Configuration: Debug Any CPU ------
  4.   HelloWorld -> c:\devprojects\Silverlight\HelloWorld\HelloWorld\Bin\Debug\HelloWorld.dll
  5.   Begin application manifest generation
  6.   Application manifest generation completed successfully
  7.   Begin Xap packaging
  8.   Creating file HelloWorld.xap
  9.   Adding HelloWorld.dll
  10.   Adding ActivityControl.dll
  11.   Adding System.ComponentModel.DataAnnotations.dll
  12.   Adding System.Windows.Controls.Data.DataForm.Toolkit.dll
  13.   Adding System.Windows.Controls.Data.Input.dll
  14.   Adding System.Windows.Controls.dll
  15.   Adding System.Windows.Controls.Navigation.dll
  16.   Adding System.Windows.Ria.dll
  17.   Adding System.Windows.Data.dll
  18.   Adding AppManifest.xaml
  19.   Xap packaging completed successfully
  20.   Creating test page
  21.   Test page created successfully
  22. ========== Rebuild All: 2 succeeded, 0 failed, 0 skipped ==========

Now confirm that the generated code made it over. Click “Show all files” display HelloWorld.Web.g.cs

image 

Notice that we can retrieve our 3 entities:

  • Customers
  • Orders
  • Order Details

Also note the we a great deal of useful boilerplate code.

image

As previously explained, views are for displaying data. Notice that “Entities” exist in the “Client” project.

Here are the steps when a user wants to see data in the browser:

  1. The client sends a query to the server
  2. The server execute the query, packages up the result in the form of an entity
  3. The server sends the entities (1 or more) back to the client

image

The client might also wish to allow the editing of data, in which case the client “submits” the data and receives a subsequent “results” object.

Adding a View

Right mouse click on the “Views” folder for the Silverlight project.

image

Add a “Silverlight Page” and call it “Customers.”

image

The next step is add a navigation link on the main page. The link will allow users to navigate to the page we just added, “Customers.xaml.”

  1. Open MainPage.xaml by right mouse clicking and choosing “View Designer.”
  2. Navigate to the <HyperlinkButton...>

image

We need to add a “Customers” hyperlink to MainPage.xaml. Notice the xaml code below at the lower arrow. He will just copy and paste “Home” and change the XAML to point to “Customers.xaml,” the page we just added.

 image

MainPage.xaml now contains the new hyperlink. Notice lines 50 to 53. Notice the “NavigateUri” is pointing to “/Customers” which will map to Customers.xaml (line 51).

 

Code Snippet

  1. <UserControl
  2. x:Class="HelloWorld.MainPage"
  3. xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  4. xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  5. xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
  6. xmlns:uriMapper="clr-namespace:System.Windows.Navigation;assembly=System.Windows.Controls.Navigation"
  7. xmlns:dataControls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.DataForm.Toolkit"
  8. xmlns:d="https://schemas.microsoft.com/expression/blend/2008" xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006"
  9. mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">
  10.  
  11.   <Grid x:Name="LayoutRoot" Style="{StaticResource LayoutRootGridStyle}">
  12.  
  13.     <Border x:Name="ContentBorder" Style="{StaticResource ContentBorderStyle}">
  14.             <navigation:Frame x:Name="ContentFrame" Style="{StaticResource ContentFrameStyle}"
  15.                               Source="/Home" Navigated="ContentFrame_Navigated"
  16.                               NavigationFailed="ContentFrame_NavigationFailed">
  17.                 <navigation:Frame.UriMapper>
  18.                   <uriMapper:UriMapper>
  19.                     <uriMapper:UriMapping Uri="" MappedUri="/Views/Home.xaml"/>
  20.                     <uriMapper:UriMapping Uri="/{pageName}" MappedUri="/Views/{pageName}.xaml"/>
  21.                   </uriMapper:UriMapper>
  22.                 </navigation:Frame.UriMapper>
  23.             </navigation:Frame>
  24.     </Border>
  25.  
  26.     <Grid Style="{StaticResource NavigationOuterGridStyle}">
  27.       <Grid x:Name="NavigationGrid" Style="{StaticResource NavigationGridStyle}">
  28.  
  29.         <Border x:Name="BrandingBorder" Style="{StaticResource BrandingBorderStyle}">
  30.           <StackPanel x:Name="BrandingStackPanel" Style="{StaticResource BrandingStackPanelStyle}">
  31.  
  32.             <ContentControl Style="{StaticResource LogoIcon}"/>
  33.             <TextBlock x:Name="ApplicationNameTextBlock" Style="{StaticResource ApplicationNameStyle}"
  34.                                Text="{Binding ApplicationStrings.ApplicationName,
  35.                                Source={StaticResource ResourceWrapper}}"/>
  36.  
  37.           </StackPanel>
  38.         </Border>
  39.  
  40.         <Border x:Name="LinksBorder" Style="{StaticResource LinksBorderStyle}">
  41.           <StackPanel x:Name="LinksStackPanel" Style="{StaticResource LinksStackPanelStyle}">
  42.  
  43.                         <HyperlinkButton x:Name="Link1" Style="{StaticResource LinkStyle}"
  44.                                      NavigateUri="/Home" TargetName="ContentFrame"
  45.                                      Content="{Binding Path=ApplicationStrings.HomePageTitle,
  46.                                      Source={StaticResource ResourceWrapper}}"/>
  47.  
  48.                         <Rectangle x:Name="Divider1" Style="{StaticResource DividerStyle}"/>
  49.                         <!--Begin add code-->
  50.                         <HyperlinkButton x:Name="Link2" Style="{StaticResource LinkStyle}"
  51.                                   NavigateUri="/Customers" TargetName="ContentFrame" Content="Customers"/>
  52.  
  53.                         <Rectangle x:Name="Divider2" Style="{StaticResource DividerStyle}"/>
  54.                         <!--End add code-->
  55.                         <HyperlinkButton x:Name="Link3" Style="{StaticResource LinkStyle}"
  56.                                      NavigateUri="/About" TargetName="ContentFrame"
  57.                                      Content="{Binding Path=ApplicationStrings.AboutPageTitle,
  58.                                      Source={StaticResource ResourceWrapper}}"/>
  59.  
  60.           </StackPanel>
  61.         </Border>
  62.  
  63.       </Grid>
  64.  
  65.       <Border x:Name="loginContainer" Style="{StaticResource LoginContainerStyle}">
  66.           <!-- LoginStatus will be added here in code behind. This is required for the
  67.                      designer view to work -->
  68.       </Border>
  69.     </Grid>
  70.  
  71.   </Grid>
  72.  
  73. </UserControl>

Note that MainPage.xaml now supports a hyperlink. Let’s run the project and see if it works as expected. Go to the “Build” menu and choose “Rebuild All.”

 

image

Let’s go back to the Customers.xaml and make some simple additions to say “hello.”

image

Change the label content to say “Customer Listing”

image

The XAML code for Customers.xaml now looks like this:

Code Snippet

  1. <navigation:Page x:Class="HelloWorld.Views.Customers"
  2.            xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3.            xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  4.            xmlns:d="https://schemas.microsoft.com/expression/blend/2008"
  5.            xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006"
  6.            mc:Ignorable="d"
  7.            xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
  8.            d:DesignWidth="640" d:DesignHeight="480"
  9.            Title="Customers" xmlns:dataInput="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.Input">
  10.     <Grid x:Name="LayoutRoot">
  11.         <dataInput:Label Height="35" HorizontalAlignment="Left" Margin="12,12,0,0"
  12.               Name="label1" VerticalAlignment="Top" Width="304" Content="Customer Listing" FontSize="18" />
  13.     </Grid>
  14. </navigation:Page>

Build the solution, then run.

image image

Click on the “Customers” menu selection and the correct result happens!

 

image

 Conclusion

This post has been useful for several reasons because we learned:

  • How work with databases and how to incorporate and ADO.NET Entity Model to our RIA Services application. However, we haven’t yet display customer data. That will happen in the next post.
  • How the relationship works between the “Domain Service” on the server and the “Domain Context” on the client (Silverlight app) to supply “entities” to the browser application (Silverlight).
  • How to add custom views to the Silverlight client. This a critical skill moving forward as we expose more and more data to the end user.