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.   Robert Martin — November 6, 2009 @ 8:02 pm    Reply

    I am CEO of a software development company in Australia and I have to say that this is without doubt the single most informative, thorough and extensive .NET blog on the entire Internet. It is so good I feel almost guilty about getting this for free. Deborah, you are amazing.

  2.   DeborahK — November 7, 2009 @ 3:46 pm    Reply

    Hi Robert –
    Thank you for the kind words.

    They really encourage me to keep going!

  3.   Andre Stegplatten — November 11, 2009 @ 7:58 am    Reply

    I have to say that this is without doubt the single most informative, thorough and extensive .NET blog on the entire Internet. It is so good I feel almost guilty about getting this for free.

  4.   Sat — November 13, 2009 @ 10:40 am    Reply

    I was tired of seeing all the examples with Entity Framework , this example is clean , clear and provide an excellent way to understand the basic concepts,
    I am trying to use your example with the ViewModel , will update my progress later. Thanks

  5.   DeborahK — November 13, 2009 @ 7:13 pm    Reply

    Hi Sat –

    Thanks! Glad this was helpful.

    Keep us posted on how you are doing!

  6.   Geoff Fox — November 21, 2009 @ 6:56 pm    Reply

    Deborah,

    This is up to your usual standard – a potentially complex topic made simple and crystal clear. I have followed your guidance since VB5 days with your book “Doing Objects” and met you the last time at the San Diego .net users group. Thanks again I will be building upon this for my work.

    Happy Thanks Giving to you and your family!

  7.   DeborahK — November 21, 2009 @ 7:03 pm    Reply

    Hi Geoff –

    Thank you for the kind words and Happy Thanksgiving to you and your family as well!

  8.   vinod — January 6, 2010 @ 9:06 am    Reply

    Add new is not working

  9.   Marcos Hass — January 6, 2010 @ 7:06 pm    Reply

    This post is really amazing !

    Some guys like me are concerned about ** how much control ** is available when you start to use a framework … and this post fills the gap. When you start a risky project you must be sure that you will be able to workaround some issues and with this information I feel more confortable.

    All other examples I’ve found in the web are “Entity Framework Centric” and this one simply explains how to put all pieces together (most of the time you already have DAL + BLL)

    Thank you very much and please don’t give up your blog !
    –marcos

  10.   HB — January 7, 2010 @ 12:56 pm    Reply

    Thanks. This was very helpful.

    As you mentioned, the next step is to change the Retrieve() method. What is the recommended way to collect data from an MSSQL database? Should I just use a stored procedure or Entity Framework?

    Could you point me to some good examples?

    Thanks.

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