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.
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.
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:
The Northwind database – building the database
The key file is instnwnd.sql.
This is only a fraction of the .sql code.
Code Snippet
- SET NOCOUNT ON
- GO
- USE master
- GO
- if exists (select * from sysdatabases where name='Northwind')
- drop database Northwind
- go
- DECLARE @device_directory NVARCHAR(520)
- SELECT @device_directory = SUBSTRING(filename, 1, CHARINDEX(N'master.mdf', LOWER(filename)) - 1)
- FROM master.dbo.sysaltfiles WHERE dbid = 1 AND fileid = 1
- EXECUTE (N'CREATE DATABASE Northwind
- ON PRIMARY (NAME = N''Northwind'', FILENAME = N''' + @device_directory + N'northwnd.mdf'')
- LOG ON (NAME = N''Northwind_log'', FILENAME = N''' + @device_directory + N'northwnd.ldf'')')
- go
- exec sp_dboption 'Northwind','trunc. log on chkpt.','true'
- exec sp_dboption 'Northwind','select into/bulkcopy','true'
- GO
- set quoted_identifier on
- GO
- /* Set DATEFORMAT so that the date strings are interpreted correctly regardless of
- the default DATEFORMAT on the server.
- */
- SET DATEFORMAT mdy
- GO
- use "Northwind"
- go
- if exists (select * from sysobjects where id = object_id('dbo.Employee Sales by Country') and sysstat & 0xf = 4)
- drop procedure "dbo"."Employee Sales by Country"
- GO
- if exists (select * from sysobjects where id = object_id('dbo.Sales by Year') and sysstat & 0xf = 4)
- drop procedure "dbo"."Sales by Year"
- GO
- if exists (select * from sysobjects where id = object_id('dbo.Ten Most Expensive Products') and sysstat & 0xf = 4)
- drop procedure "dbo"."Ten Most Expensive Products"
- GO
Start Microsoft SQL Server Management Studio and choose, “File, Open, File”
Open instnwnd.sql and go to SQL Server Management Studio and hit the “f5” key or go to the menu and choose “Query, Execute.”
Notice that we have a Northwind database. We will work with some of the tables here in our Silverlight RIA Services project.
The Northwind database – adding and ADO.NET Entity Model
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.
- This will hold our ADO.NET Entity Model that Silverlight RIA Services will consume.
- The ADO.NET Entity Model has a lot of useful functionality and will help as a layer of abstraction for our Silverlight application
- See 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 for some reasons why we like working with “entities” instead of relational data.
Silverlight will use an ADO.NET Entity Data Model to query the data store.
We will generate our entity model using the previously created Northwind database.
Select the Northwind database that your created in previous steps:
Make sure to select 3 tables:
- Customer
- Orders
- Order Details
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.”
In the HelloWorld.Web project add a “New Item to the “Services” folder.
Perform the following:
- Choose Domain Service Class
- Give a name of NorthWindDomainService
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)
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.
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)
Next, click on “Show All Files”
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.
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
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.
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.
Code Snippet
- public IQueryable<Customer> GetCustomersInUK()
- {
- return this.ObjectContext.Customers.Where(e => (e.Country == "OK"));
- }
Let’s compile to make sure there are no mistakes.
Code Snippet
- ------ Rebuild All started: Project: HelloWorld.Web, Configuration: Debug Any CPU ------
- HelloWorld.Web -> c:\devprojects\Silverlight\HelloWorld\HelloWorld.Web\bin\HelloWorld.Web.dll
- ------ Rebuild All started: Project: HelloWorld, Configuration: Debug Any CPU ------
- HelloWorld -> c:\devprojects\Silverlight\HelloWorld\HelloWorld\Bin\Debug\HelloWorld.dll
- Begin application manifest generation
- Application manifest generation completed successfully
- Begin Xap packaging
- Creating file HelloWorld.xap
- Adding HelloWorld.dll
- Adding ActivityControl.dll
- Adding System.ComponentModel.DataAnnotations.dll
- Adding System.Windows.Controls.Data.DataForm.Toolkit.dll
- Adding System.Windows.Controls.Data.Input.dll
- Adding System.Windows.Controls.dll
- Adding System.Windows.Controls.Navigation.dll
- Adding System.Windows.Ria.dll
- Adding System.Windows.Data.dll
- Adding AppManifest.xaml
- Xap packaging completed successfully
- Creating test page
- Test page created successfully
- ========== 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
Notice that we can retrieve our 3 entities:
- Customers
- Orders
- Order Details
Also note the we a great deal of useful boilerplate code.
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:
- The client sends a query to the server
- The server execute the query, packages up the result in the form of an entity
- The server sends the entities (1 or more) back to the client
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.
Add a “Silverlight Page” and call it “Customers.”
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.”
- Open MainPage.xaml by right mouse clicking and choosing “View Designer.”
- Navigate to the <HyperlinkButton...>
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.
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
- <UserControl
- x:Class="HelloWorld.MainPage"
- xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
- xmlns:uriMapper="clr-namespace:System.Windows.Navigation;assembly=System.Windows.Controls.Navigation"
- xmlns:dataControls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.DataForm.Toolkit"
- xmlns:d="https://schemas.microsoft.com/expression/blend/2008" xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006"
- mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">
- <Grid x:Name="LayoutRoot" Style="{StaticResource LayoutRootGridStyle}">
- <Border x:Name="ContentBorder" Style="{StaticResource ContentBorderStyle}">
- <navigation:Frame x:Name="ContentFrame" Style="{StaticResource ContentFrameStyle}"
- Source="/Home" Navigated="ContentFrame_Navigated"
- NavigationFailed="ContentFrame_NavigationFailed">
- <navigation:Frame.UriMapper>
- <uriMapper:UriMapper>
- <uriMapper:UriMapping Uri="" MappedUri="/Views/Home.xaml"/>
- <uriMapper:UriMapping Uri="/{pageName}" MappedUri="/Views/{pageName}.xaml"/>
- </uriMapper:UriMapper>
- </navigation:Frame.UriMapper>
- </navigation:Frame>
- </Border>
- <Grid Style="{StaticResource NavigationOuterGridStyle}">
- <Grid x:Name="NavigationGrid" Style="{StaticResource NavigationGridStyle}">
- <Border x:Name="BrandingBorder" Style="{StaticResource BrandingBorderStyle}">
- <StackPanel x:Name="BrandingStackPanel" Style="{StaticResource BrandingStackPanelStyle}">
- <ContentControl Style="{StaticResource LogoIcon}"/>
- <TextBlock x:Name="ApplicationNameTextBlock" Style="{StaticResource ApplicationNameStyle}"
- Text="{Binding ApplicationStrings.ApplicationName,
- Source={StaticResource ResourceWrapper}}"/>
- </StackPanel>
- </Border>
- <Border x:Name="LinksBorder" Style="{StaticResource LinksBorderStyle}">
- <StackPanel x:Name="LinksStackPanel" Style="{StaticResource LinksStackPanelStyle}">
- <HyperlinkButton x:Name="Link1" Style="{StaticResource LinkStyle}"
- NavigateUri="/Home" TargetName="ContentFrame"
- Content="{Binding Path=ApplicationStrings.HomePageTitle,
- Source={StaticResource ResourceWrapper}}"/>
- <Rectangle x:Name="Divider1" Style="{StaticResource DividerStyle}"/>
- <!--Begin add code-->
- <HyperlinkButton x:Name="Link2" Style="{StaticResource LinkStyle}"
- NavigateUri="/Customers" TargetName="ContentFrame" Content="Customers"/>
- <Rectangle x:Name="Divider2" Style="{StaticResource DividerStyle}"/>
- <!--End add code-->
- <HyperlinkButton x:Name="Link3" Style="{StaticResource LinkStyle}"
- NavigateUri="/About" TargetName="ContentFrame"
- Content="{Binding Path=ApplicationStrings.AboutPageTitle,
- Source={StaticResource ResourceWrapper}}"/>
- </StackPanel>
- </Border>
- </Grid>
- <Border x:Name="loginContainer" Style="{StaticResource LoginContainerStyle}">
- <!-- LoginStatus will be added here in code behind. This is required for the
- designer view to work -->
- </Border>
- </Grid>
- </Grid>
- </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.”
Let’s go back to the Customers.xaml and make some simple additions to say “hello.”
Change the label content to say “Customer Listing”
The XAML code for Customers.xaml now looks like this:
Code Snippet
- <navigation:Page x:Class="HelloWorld.Views.Customers"
- xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="https://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006"
- mc:Ignorable="d"
- xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
- d:DesignWidth="640" d:DesignHeight="480"
- Title="Customers" xmlns:dataInput="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.Input">
- <Grid x:Name="LayoutRoot">
- <dataInput:Label Height="35" HorizontalAlignment="Left" Margin="12,12,0,0"
- Name="label1" VerticalAlignment="Top" Width="304" Content="Customer Listing" FontSize="18" />
- </Grid>
- </navigation:Page>
Build the solution, then run.
Click on the “Customers” menu selection and the correct result happens!
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.
Comments
Anonymous
September 21, 2010
This and the previous post were very thorough and helpful to Silverlight newcomers. Are there more that get into CRUD operations?Anonymous
September 21, 2010
HI, Can you please explain How Add, Update and Delete from domainservice are mapping in Auto Generate code.Anonymous
November 04, 2010
Hi Bruno and thanks for your wonderful, well-explained post. I have in my database a User, Role and UserRole table, I want to use my custom tables, not the aspnetdb's, how do I do it?Anonymous
November 04, 2010
Hi Bruno and thanks for your wonderful, well-explained post. I have in my database a User, Role and UserRole table, I want to use my custom tables, not the aspnetdb's, how do I do it?