Deborah's Developer MindScape






         Tips and Techniques for Web and .NET developers.

November 5, 2009

Silverlight, RIA Services, and Your Business Objects

Filed under: ASP.NET RIA Services,C#,Silverlight,VB.NET @ 3:12 pm

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:

  1. 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.
  2. Build a WCF service that provides your business objects to your Silverlight application. You can find out more about this option here.
  3. 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.

[To use RIA with Entity Framework, there is video walkthrough here.]

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.

image

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:

  1. If you don’t have it, download and install Silverlight 3 using the information provided here.
  2. 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)
  3. Create a new Visual Studio Solution.
  4. Create a new Class Library project in that solution and build your business objects. This example uses the Customer and Customers classes defined below.

In C#:

public class Customer
{
    public int CustomerId { get; set; }
    public string LastName { get; set; }
    public string FirstName { get; set; }
    public string EmailAddress { get; set; }
}

public class Customers
{
   public static List<Customer> Retrieve()
   {
      List<Customer> custList = new List<Customer>
                    {new Customer()
                          { CustomerId = 1,
                            FirstName="Bilbo",
                            LastName = "Baggins",
                            EmailAddress = "bb@hob.me"},
                    new Customer()
                          { CustomerId = 2,
                            FirstName="Frodo",
                            LastName = "Baggins",
                            EmailAddress = "fb@hob.me"},
                    new Customer()
                          { CustomerId = 3,
                            FirstName="Samwise",
                            LastName = "Gamgee",
                            EmailAddress = "sg@hob.me"},
                    new Customer()
                          { CustomerId = 4,
                            FirstName="Rosie",
                            LastName = "Cotton",
                            EmailAddress = "
rc@hob.me"}};
      return custList;
   }
}

In VB:

Public Class Customer

    Private _CustomerId As Integer
    Public Property CustomerId() As Integer
        Get
            Return _CustomerId
        End Get
        Set(ByVal value As Integer)
            _CustomerId = value
        End Set
    End Property

    Private _FirstName As String
    Public Property FirstName() As String
        Get
            Return _FirstName
        End Get
        Set(ByVal value As String)
            _FirstName = value
        End Set
    End Property

    Private _LastName As String   
    Public Property LastName() As String
        Get
            Return _LastName
        End Get
        Set(ByVal value As String)
            _LastName = value
        End Set
    End Property

    Private _EmailAddress As String
    Public Property EmailAddress () As String
        Get
            Return _EmailAddress
        End Get
        Set(ByVal value As String)
            _EmailAddress = value
        End Set
    End Property
End Class

Public Class Customers

    Public Shared Function Retrieve() As List(Of Customer)
        Dim custList As New List(Of Customer)
        custList.Add(New Customer With {.CustomerId = 1, _
                                        .LastName = "Baggins", _
                                        .FirstName = "Bilbo", _
                                        .EmailAddress = "bb@hob.me"})
        custList.Add(New Customer With {.CustomerId = 2, _
                                        .LastName = "Baggins", _
                                        .FirstName = "Frodo", _
                                        .EmailAddress = "fb@hob.me"})
        custList.Add(New Customer With {.CustomerId = 3, _
                                        .LastName = "Gamgee", _
                                        .FirstName = "Samwise", _
                                        .EmailAddress = "sg@hob.me"})
        custList.Add(New Customer With {.CustomerId = 4, _
                                        .LastName = "Cotton", _
                                        .FirstName = "Rosie", _
                                        .EmailAddress = "rc@hob.me"})
        Return custList
    End Function

End Class

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.

image

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.

In C#:

[System.ComponentModel.DataAnnotations.Key()]
public int CustomerId { get; set; }

In VB:

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.

image

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

2. Be sure to enable RIA Services.

image

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:

image

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.

image

2. Be sure to enable client access.

image

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.

3. Click OK.

Visual Studio creates the basic structure of your Domain Service class as shown below.

In C#:

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;

    // TODO: Create methods containing your application logic.
    [EnableClientAccess()]
    public class CustomerService : DomainService
    {
    }
}

In VB:

Option Strict Off
Option Explicit On

Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.ComponentModel.DataAnnotations
Imports System.Linq
Imports System.Web.DomainServices
Imports System.Web.Ria
Imports System.Web.Ria.Data

‘TODO: Create methods containing your application logic.
<EnableClientAccess()>  _
Public Class CustomerService
    Inherits DomainService
End Class

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.

image

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:

image

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.

In C#:

public IEnumerable<Customer> GetCustomers()
{
    return Customers.Retrieve();
}

In VB:

Public Function GetCustomers() As IEnumerable(Of Customer)
    Return Customers.Retrieve()
End Function

Note that this must be a method and not a property. If you attempt to use a property here, the compiler won’t generate the required code.

The GetCustomers method simply calls the static/shared Retrieve method of the Customers class (defined at the beginning of this post).

Accessing the Domain Service Class from Silverlight

Finally! You are ready to use your business object from Silverlight by way of the Domain Service class.

1. Open the Silverlight Application project.

2. This example uses a grid to display the customer data, so set a reference to System.windows.Controls.Data.

3. To use the RIA Service controls, set a reference to System.Windows.Ria.Controls.

3. Open the MainPage.xaml file that was created for you in the Silverlight Application project.

4. Set up the XML namespaces.

<UserControl x:Class="SLCSharp.MainPage"
 xmlns="
http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml
xmlns:d=
http://schemas.microsoft.com/expression/blend/2008
xmlns:mc=http://schemas.openxmlformats.org/markup-compatibility/2006
 xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
 xmlns:riaControls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Ria.Controls"
 xmlns:domain="clr-namespace:SLCSharp.Web"
mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">

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
  • xmlns:domain – Defines the associated ASP.NET namespace, required when using RIA services.

5. Add code to display a bound grid.

<Grid x:Name="LayoutRoot">
    <riaControls:DomainDataSource x:Name="CustomerSource"
                        QueryName="GetCustomers" AutoLoad="True">
        <riaControls:DomainDataSource.DomainContext>
            <domain:CustomerContext/>
        </riaControls:DomainDataSource.DomainContext>
    </riaControls:DomainDataSource>

    <data:DataGrid x:Name="CustomerList"
          ItemsSource="{Binding Data, ElementName=CustomerSource}">
    </data:DataGrid>
</Grid>

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:

image

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

  1.   Frank — October 13, 2010 @ 11:47 am    Reply

    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.

    Thanks!

  2.   Frank — October 15, 2010 @ 9:58 am    Reply

    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, … ”

  3.   Susette McCann — February 3, 2011 @ 11:39 am    Reply

    Thanks so much for a great article. I’ve always worked with business objects and this gives me the starting point to be able to do so in a Silverlight app.

  4.   blaise — February 24, 2011 @ 4:10 am    Reply

    I must admit this post seems to be the best I’ve read in last month about ria services (as mentionned, not E.F. centric). Let’s make a trial of this architecture 😉

  5.   Faye — March 28, 2011 @ 2:13 pm    Reply

    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

  6.   DeborahK — March 29, 2011 @ 11:25 pm    Reply

    Hi Faye –

    Have you loaded on Visual Studio SP 1? It just came out earlier this month (March). It contains RIA Services.

    Hope this helps.

  7.   Manny — April 26, 2011 @ 3:55 pm    Reply

    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.

RSS feed for comments on this post. TrackBack URI

Leave a comment

© 2019 Deborah's Developer MindScape   Provided by WPMU DEV -The WordPress Experts   Hosted by Microsoft MVPs