1. Problem
You need to create a Silverlight application that displays data from a database.
2. Solution
Take advantage of
Microsoft WCF RIA Services and the Silverlight Business Application
template to build the foundation of a LOB application.
3. How It Works
In previous versions of
Silverlight, you had to write a lot of custom code to access data in a
Silverlight application. With Silverlight 4 and WCF RIA Services, you
can easily make data available to Silverlight in a robust way with full
support for XAML databinding, validation, and custom extensions to
generated code.
When you install the
Silverlight 4 tools, it also installs WCF RIA Services, which includes
all of the functionality to make data easily accessible in Silverlight.
WCF RIA Services includes support to generate needed middle-tier classes
that run on the web service. These classes access data from the
database and provide end points that the generated classes can access
from a Silverlight application.
The first step is to create a
data model that lives in the middle tier. You create data models using
the ADO.NET Entity Framework classes that can be consumed by WCF RIA
Services.
Once you have an ADO.NET
Entity Framework data model available on the middle tier, you create
highly extensible Domain Services that provide end-points for
Silverlight. The Domain Service class provides services that make the
Entities from the model available via a WCF end-point. This approach
provides a robust programming model in order to perform CRUD operations
on the underlying database tables. You can program against domain
entities using LINQ to Objects. You can also add additional methods to
the Domain Services that implement business logic without breaking the
model or the code generation.
Connecting the endpoints
to make the Entity classes available in Silverlight is very simple
because the WCF RIA Services framework automatically generates
Silverlight client-side code to access the Domain Service end-points for
"linked" Silverlight applications. When you install WCF RIA Services,
it modifies the New Silverlight Application Wizard and the Silverlight
project properties to include an Enable WCF RIA Services checkbox.
Enabling WCF RIA Services connects a Silverlight application to the
middle tier hosting the related Domain Services.
Once on the client, you can write code to instantiate a DomainContext, which keeps track of changes as you access and updates Entities in Silverlight.
4. The Code
First, create a Silverlight
application and check the Enable WCF RIA Services checkbox to establish
the WCF RIA Link. You can verify this by looking at the Silverlight tab
in the project properties for Recipe 4 as shown in Figure 1.
When the WCF RIA Services
link is established, any domain services created in the TestWeb web
application are made available within the Silverlight project via the
code-generation functionality built into the WCF RIA Services framework.
Figure 2 shows the Solution Explorer tool window for Recipe 4 with hidden files and folders displayed and all folders expanded.
With hidden folders displayed, you see a folder named Generated_Code with a generated code file named TestWeb.g.cs. This code file is brought in via WCF RIA Services code generation and is linked to the TestWeb web project, which is also where the file gets its default name of TestWeb.g.cs.
The contents are auto-generated, not doing much more than establishing
the WebContext, which makes web application services such as
authentication, authorization, etc. available in a Silverlight
application
Now, shift gears to the
middle tier and leave your Silverlight application ready to receive the
automatically generated client-side code. You will create an Entity
Framework data model that contains all of the available entities and
then create a Domain Service to access it. First, create two folders
named DataModel and DomainService to hold the Entity Framework model and Domain Services, respectively.
Right-click on the data model
folder and select Add New Item to bring up the project items dialog.
Click Data on the left to filter the project items available and select
ADO.NET Entity Data Model. Name it Northwind.edmx
and click Add to bring up the Entity Data Model Wizard. Select Generate
from database and click Next. Click New Connection... to create a new
database connect to the Northwind database or select an existing
connection if present. Note that the connection string is saved to the Web.config file so you can edit this file as the project is moved between a development, test, and production environment.
In the Choose your
Database Objects page of the wizard, select all tables, and click
Finish, accepting the defaults. This results in the model shown in Figure 3.
NOTE
The ADO.NET Entity Framework
is a very powerful object to relational modeling tool. For more
information on the ADO.NET Entity Framework, please go to
msdn.microsoft.com/data/.
You are not going to
customize the data model any further. Instead, create the Domain Service
by first compiling the project. Compiling the project makes the newly
created data model available so that the Add New Domain Service Class
wizard can detect that it is available and thus create the service. The
newly created service makes the Person Entity available to the
Silverlight application. Right-click on the Domain Service folder,
select Add | New Item..., and click on Web to filter the project
templates so that the Domain Service Class item template is visible.
Give it a name of NorthwindSimpleDomainService and click Add. This brings up the Add New Domain Service Class wizard as shown in Figure 4.
Check all of the options
available to generate a read-only OData endpoint, enable editing on all
of the available entities in WCF RIA Services, and generate associated
classes for metadata. This results in two additional class files and an
updated Web.config file in the TestWeb project. The two new class files are NorthwindDomainService.cs and NorthwindDomainService.metadata.cs in the DomainService folder.
The NorthwindDomainService.cs file is the new domain service. It contains the methods shown in Figure 5.
The generated code
provides methods to get a list of the various entities as well as
methods to perform CRUD actions on entities. As the comments note in Figure 9-12, you can customize the methods, add methods, etc., as needed to build your domain service. So, add a method called GetCustomersByCity to return a list of Customers whose City starts with the passed in string:
public IQueryable<Customer> GetCustomersByCity(string value)
{
var customerlist = from c in this.ObjectContext.Customers
where c.City.StartsWith(value)
select c;
return customerlist;
}
The other generated class, NorthwindDomainService.metadata.cs, contains the metadata class for the Person entity. Figure 6 shows the top portion of the class declaration.
For more detail on how to
modify these files, such as how to add custom query methods to the
Domain Service and to add validation to the metadata class, see the
previous recipe. For this recipe, you now switch your focus to the
client-side generated code in TestWeb.g.cs, located in the hidden folder of the Generated_Code folder of the Silverlight project.
After establishing the WCF RIA Link between Recipe 4 and TestWeb, and then creating the Adventure Works Domain Service, you build the project. The TestWeb.g.cs file in the Recipe 4
Silverlight project now has client-side code to allow access to your
Northwind Data Model containing the imported entities available in the
Northwind Data Model.
You create a simple UI of a DataGrid and write some code to databind it to the client-side generated code manually. You drag a DataGrid on to MainPage.xaml and name it CustomersDataGrid. In the codebehind, add two using clauses to bring in the client-side generated code:
using TestWeb.DomainService;
using TestWeb.DataModel;
Next, modify the MainPage() constructor to manually call into the WCF RIA Services generated code. Here is the code:
public MainPage()
{
InitializeComponent();
NorthwindDomainContext context = new NorthwindDomainContext();
CustomersDataGrid.ItemsSource = context.Customers;
context.Load<Customer>(context.GetCustomersQuery());
}
Create an instance of the domain context, databind the CustomersDataGrid to the Customers entity collection, and then call Load on the NorthwindDomainContext, passing in the appropriate query resulting in the customer data loading as shown in Figure 7.