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.   tom — March 31, 2010 @ 11:07 am    Reply

    this is a great article! it’s nice to see something about how to integrate this with existing work, when most of what we’re seeing from MS is only focussed on new, simple projects.

    To that end, we found this article in trying to resolve a problem integrating into an existing project. We found that if you’re actually adding to an existing site, some of the configs don’t get applied. That was not noted in your article because you created a new ASP.NET site, even though you’re targetting an ‘existing’ POCO layer.

    if you create the POCO, then create the ASP.NET, THEN add the SL, you will find there are some WPF configs missing for the ‘DomainServiceModule’ and the ‘serviceHostingEnvironment.’ these missing configs cause the dreaded, “Load operation failed for query xx. The remote server returned an error: NotFound.”

  2.   SHannon — April 9, 2010 @ 10:36 am    Reply

    Hate to post a question.. but can’t figure it out.. I’ve tried to follow the code above and i can build the solution with no errors, but when i run it, i get an error 4004. Message:System.Windows.Ria.DomainException: An error occurred while loading data through the GetCustomers query on Domain context of type

    and that is where the message ends…
    hope someone can help.. this POCO would be nice to get familiar with.
    thanks

  3.   Srinivas — May 6, 2010 @ 7:40 pm    Reply

    Hi,

    We have an existing project for Silverlight3 & WCF web services. We have created two separate solutions, one for Silverlight UI (with Web project) and another solution for WCF web services using WCF Service Library template projects (one for each application area).

    Can you please guide me (high level) what changes that need to be made for WCF web projects to enable RIA services and UI side to consume? Currently, we use Add Service reference to .svc file and make async calls to web services. We are using VS2008.

    Great article and gave me some confidence in moving forward with our existing projects using RIA services. thanks

    I really appreciate your help.

    – Srinivas

  4.   DeborahK — May 6, 2010 @ 8:05 pm    Reply

    Hi Srinivas –

    I have not done Silverlight 3 with WCF. I have only been using RIA with my own business objects. So I don’t have any answers for you on that topic.

  5.   Mark Mac — May 25, 2010 @ 4:51 am    Reply

    Great stuff, finally an example of RIA Services that is not using the Entity Framework, I new this was possible but couldn’t for the life of me find an example of RIA Services using POCO.

  6.   ste — June 17, 2010 @ 9:08 am    Reply

    Finally! A tutorial on RIA Services without the damn Entity Framework.

    Great article, helped me a lot. Thanks!

    Long live POCO!! 🙂

  7.   TalMcMahon — July 8, 2010 @ 12:48 pm    Reply

    I really enjoyed the post, I am curious what do you do about functions and Methods from your PCOC objects. seems like we just get property bags.

  8.   DeborahK — July 8, 2010 @ 5:04 pm    Reply

    There are several ways to call methods, depending on what they do. I am planning a set of blog posts demonstrating these techniques in the near term future.

  9.   Mike Griffin — September 3, 2010 @ 3:52 pm    Reply

    The problem is the objects aren’t editable, if you try to use the details grid it wont work, this is very frustrating because it only works for architectures that implement a DomainContext and therefully fully implement linq and so on, so in reality, at least thus far, RIA is really for the EF

  10.   DeborahK — September 3, 2010 @ 7:48 pm    Reply

    Hi Mike –

    It was great talking with you. We are using RIA for our project and NOT EF. So far we are still in the prototyping/design phase, but we have been able to get editing to work using the techniques I presented here:

    http://msmvps.com/blogs/deborahk/archive/2010/07/19/sl-ria-poco-update.aspx

    Hope this helps you!

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