Silverlight, RIA Services, and Your Business Objects

With RIA Services, it is easy to use your own business objects in your Silverlight application… once you have the basic plumbing in place. However, there are quite a few steps required to set up that plumbing. This post details the process of hooking up your business objects, RIA Services, and Silverlight.

So … you follow best practices and build business objects for all of the entities involved in your application. Or maybe you generate those business objects with something like Entity Framework (EF), Linq to SQL or other similar tool. In any case, you now want to use those business objects from a Silverlight application.

Seems like it should be easy, right? Just define a reference from your Silverlight application to your business object component and proceed just like with your WinForms or ASP.NET application. But no.

Silverlight does not allow you to set a reference to a non-Silverlight component. There are a number of ways you can deal with this:

Use a Silverlight class library project type and build your business objects in there. Not a good solution if you are using those same business objects with other user interfaces.

Build a WCF service that provides your business objects to your Silverlight application. You can find out more about this option here.

Use Rich Internet Application (RIA) Services. This is a new Microsoft technology that is currently out in preview.

This post demonstrates option #3: Using RIA Services. The example presented in this post uses business objects you build yourself. These "home made" business objects are often referred to as POCO, or plain old CLR objects. Use the techniques presented in this post any time you start a new Silverlight application and want to access your POCOs from that application.

The basic idea behind RIA Services is to use an ASP.NET application between your business object component and your Silverlight application to provide the communication between the two as shown below.

Starting right to left, you build your business objects in a Class Library component. This example uses a Customer class to define a customer and a Customers class to provide the list of customers.

The ASP.NET application has a standard project reference to the POCO class library. The ASP.NET application includes a Domain Service class, called CustomerService in this example, that calls the desired methods in the POCO class library.

The Silverlight application has an RIA Services link to the ASP.NET Web application. When the Silverlight application is compiled, it generates a client-side copy of the entity referenced by the ASP.NET application. In this case, it generates a Customer class. It also generates a entity context (CustomerContext in this case) that can be used for Silverlight data binding.

The remainder of this post walks through this process one step at a time.

Prerequisites

Before you can begin, there are some prerequisite steps:

If you don’t have it, download and install Silverlight 3 using the information provided here.

Download and install RIA Services using the information provided here. (You may have already done this if you followed all of the instructions in step #1)

Create a new Visual Studio Solution.

Create a new Class Library project in that solution and build your business objects. This example uses the Customer and Customers classes defined below.

The C# code here uses auto-implemented properties to shorten the property syntax. The VB code uses the full property syntax.

In a real application, the Retrieve method would collect the data from the database. This example uses hard-coded values to make it easier for you to try this code without having to set up data access.

Decorating your Business Objects

Once you have the prerequisites complete, you need to add some attributes to your business objects so they are recognized by RIA Services when it generates the Silverlight entity.

1. Open the solution containing your business objects.

2. Open the Class Library project properties window for the project containing your business objects.

3. Add a reference to System.ComponentModel.DataAnnotations.

I had two of these. Be sure to pick the one from the Microsoft SDKs\RIA Services directory.

This namespace contains the attributes you need to annotate your business objects for RIA Services.

4. Add the Key attribute on the property that represents the unique key of the business object.

Private _CustomerId As Integer <System.ComponentModel.DataAnnotations.Key()> _ Public Property CustomerId() As Integer Get Return _CustomerId End Get Set(ByVal value As Integer) _CustomerId = value End Set End Property

In this example, CustomerId is the unique key, so it is marked with the Key attribute.

5. Optionally, add RIA attributes for validation as desired. (More on this in a future post.)

Adding the Silverlight Project

Now that the business objects are ready, you can add the Silverlight project to your solution. This will automatically generate the associated ASP.NET project as well.

1. Add a new Silverlight Application to your solution.

You can create your Silverlight project in VB or in C#.

2. Be sure to enable RIA Services.

3. Click OK.

Visual Studio creates both the Silverlight project and the associated ASP.NET project. At runtime, the ASP.NET project launches the Silverlight project. The ASP.NET project also provides access to your business objects through RIA services.

NOTE: If you already have a Silverlight project that you wish to use with RIA Services, you can enable .NET RIA Services in the Silverlight project properties window:

Adding the Domain Service Classes

The ASP.NET application provides the communication between your business objects and the Silverlight application. This is accomplished with RIA Services by creating a set of Domain Service classes in the ASP.NET application.

1. Add a Domain Service class to the ASP.NET application.

2. Be sure to enable client access.

Notice that the bottom of this dialog is empty. If you used Entity Framework to generate your entities, they would appear in this dialog. But since this example uses POCOs, there won’t be any entities displayed.

namespace SLCSharp.Web { using System; using System.Collections.Generic; using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Web.Ria; using System.Web.Ria.Data; using System.Web.DomainServices;

NOTE: IMMEDIATELY change the Option Strict Off to Option Strict ON OR remove the lines entirely if you have them both on by default in your Compile options.

You can also remove any import statements for namespaces you already import through the References tab of the Properties window.

Accessing Your Business Objects From the Domain Service Class

The code to access your business objects goes into the Domain Service class created above. You can think of the Domain Service class as a wrapper around your business object members that provides a way for Silverlight to access the object properties and methods.

Any time you need to access any properties or call any methods on your business objects, you need to write a wrapper for that access in the Domain Service class.

Normally, you create one Domain Service class for each entity. So if your business objects included Customer/Customers, Purchase/Purchases, Invoice/Invoices, for example, you would create a CustomerService, PurchaseService, and InvoiceService class.

1. In your ASP.NET project containing your Domain Service class, set a reference to your business object component.

My sample project has two sets of business objects, one in VB and one in C#. You can access business objects in either language.

2. In the Domain Service class, import the namespace for the business object component.

In C#:

using BoCSharp;

In VB:

Imports BoVB

Or if you are using VB, import this namespace using the References tab of the Properties window:

3. Add the code that wraps the functionality of your business object.

For the purposes of this post, the code retrieves the set of customers.

NOTE: If you copy and paste these namespaces into your application, be sure that you change the values shown in red. The x:Class is the name of the associated code behind class file. the xmlns:domain is the name of the associated ASP.Net application namespace.

These namespaces are as follows:

xmlns – Default for Silverlight and WPF.

xmlns:x – XAML-defined language elements for Silverlight and WPF, required for even basic features such as mapping a XAML file to its code behind file using x:Class.

xmlns:data – XAML data controls, such as the DataGrid.

xmlns:riaControls – RIA Service controls, such as the DomainDataSource

This code sets up an RIA Services DomainDataSource defining the source of the data for this UserControl. It defines a name (CustomerSource) and a QueryName (GetCustomers). The query name must match the name of the method to call in the Domain Service class.

It also sets a DomainContext, which associates the DomainDataSource with the Domain Service. This must match the name of the DomainContext in the generated code. Intellisense should help you define the correct name.

The DataGrid element uses the ItemsSource attribute to define the binding source. In this case, it is CustomerSource. This name must match the name given to the DomainDataSource.

6. Run it.

If everything works, it should appear as follows:

Now you can use your mad skills with styles and other Silverlight features to make this look nice.

Wow! That seemed like a lot of work.

The good news is that once you set this up, adding more features is easy:

Add appropriate wrappers to the ASP.Net project using the Domain Service classes.

Use the wrappers as needed from your Silverlight application.

Enjoy!

27 Comments

This is probably a silly question .. lets say I have a solution with 5 pages .. each page uses the same load entity (observable collection) from a SQL database as all of the other pages. I want to CRUD the observable collection on each page. Is there any way I can go to the server once, get the load entity, then on each of the other pages access the load entity without keep going back to the Server? I assume the load entity is always bound to the server, so if i update it, i can make sure the server file is updated.

got the following suggestion from Kevin Dockx, a co-author of a fabulous book .. Microsoft Silverlight 4 Data and Services Cookbook:
“It appears you’re using a DomainContext instance on each page, right? One of the ways to solve your problem would be to create some kind of local state context container, eg: a class which holds a static instance of your DomainContext. You can access this instance from each of your pages, and reuse the product entities once they’ve been loaded – if the Products have already been loaded: don’t execute the load query again.
Another interesting thing to look into might be “LoadBehavior”: with this (add as parameter to your load op), you can control what RIA Services should do when it returns from the server with entities which are already in your context: keep ‘em, overwrite ‘em, … ”

I am new to RIA Services and and I am stuck on 3. Add a reference to System.ComponentModel.DataAnnotations.

I cant find the dataAnotaions dll that you are refering to. I reinstalled the Silverlight4_tools and it didnt put it in there? I have it all set up except for that and I cant add the referance to the xaml file.
xmlns:riaControls=”clr-namespace:System.Windows.Controls;assembly=System.Windows.Ria.Controls”
Thanks!
Faye

Thank you so much. Just what I was looking for. In most of the apps, the architecture is predefined and I can’t really use a straight forward EF Domain Service. Your blog got me a step closer to my solution.