Deborah's Developer MindScape






         Tips and Techniques for Web and .NET developers.

July 19, 2010

The World’s Simplest Silverlight/RIA/POCO Example

Filed under: ASP.NET RIA Services,C#,Silverlight,VB.NET @ 10:33 am

This post demonstrates how to use Silverlight and WCF RIA Services to access YOUR server-side business objects to build a line of business application.

This particular example is as absolutely simple as possible to help you get up and running with these technologies. To meet this goal, this first post covers only how to retrieve data. Later posts will cover update operations.

So first, the prerequisites:

1) Download and install Silverlight 4 and WCF RIA Services 1.0.

Visual Studio 2010 comes with Silverlight 3. You need to download and install the Silverlight 4 Tools for Visual Studio 2010 from here. It comes with WCF RIA Services, so no additional download is required for RIA.

2) Download the Silverlight Toolkit.

This download provides many additional controls and themes. You can download it from here.

3) Build the Business Layer component.

When building a Silverlight/RIA application, you have probably already built your business layer and have business objects that you want to use in your Silverlight application. But if not, you need to do that first.

This example uses an overly simplified business layer component with the Customer class shown below.

Build a standard Class Library project and add the following code:

In C#:

using System.Collections.Generic;

namespace ACM.BLCSharp
{
    /// <summary>
    /// Manages a customer
    /// </summary>
    public class Customer
    {
        public int CustomerId { get; set; }
        public string LastName { get; set; }
        public string FirstName { get; set; }
        public string EmailAddress { get; set; }

        /// <summary>
        /// Retrieves a list of customers.
        /// </summary>
        /// <returns></returns>
        /// <remarks>
        /// In a "real" application, this code would
        /// call a data access component that retrieves
        /// the data from a database.
        /// </remarks>
        public 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:

”’ <summary>
”’ Manages a customer
”’ </summary>
”’ <remarks></remarks>
”’ <editHistory></editHistory>
Public Class Customer
    Public Property CustomerId As Integer
    Public Property FirstName() As String
    Public Property LastName() As String
    Public Property EmailAddress() As String

    ”’ <summary>
    ”’ Retrieves a list of customers.
    ”’ </summary>
    ”’ <returns></returns>
    ”’ <remarks>
    ”’ In a "real" application, this code would
    ”’ call a data access component that retrieves
    ”’ the data from a database.
    ”’ </remarks>
    Public Function Retrieve() As List(Of Customer)
        Dim custList As New List(Of Customer) From
                    {New Customer() With
                          {.CustomerId = 1,
                            .FirstName = "Bilbo",
                            .LastName = "Baggins",
                            .EmailAddress = "bb@hob.me"},
                    New Customer() With
                          {.CustomerId = 2,
                            .FirstName = "Frodo",
                            .LastName = "Baggins",
                            .EmailAddress = "fb@hob.me"},
                    New Customer() With
                          {.CustomerId = 3,
                            .FirstName = "Samwise",
                            .LastName = "Gamgee",
                            .EmailAddress = "sg@hob.me"},
                    New Customer() With
                          {.CustomerId = 4,
                            .FirstName = "Rosie",
                            .LastName = "Cotton",
                            .EmailAddress = "rc@hob.me"}}
        Return custList
    End Function
End Class

NOTE: This code does not use a data access layer at this time. To keep this example as simple as possible, the Retrieve method "mocks" a retrieve that would call your data access component and retrieve the data from the database. This code will be replaced in a later post to actually access a database.

NOTE: Normally I build a Customer class (singular) with the properties and methods that mange a singe customer and a Customers class (plural) that works with a list of those customers. The functionality for both were added to one class to keep this example as simple as possible.

Once the prerequisites are in place, we can get started.

STEP 1: Attribute your business objects to work with Silverlight

There are several different attributes you can define in your business objects so they work better with Silverlight, but in keeping with our goal of creating the simplest Silverlight/RIA/POCO example, you are only required to have one.

For WCF RIA services to work properly, you must have the Key attribute defined on the property that represents the unique key for your business object. This is most often the property of the class that stores the primary key value from your underlying table. In this example, it is the CustomerId property.

The Key attribute is defined in System.ComponentModel.DataAnnotations. So you must add a reference to that namespace and import it to use it.

In C#:

using System.ComponentModel.DataAnnotations;

[Key()]
public int CustomerId { get; set; }

In VB:

Imports System.ComponentModel.DataAnnotations

<Key()>
Public Property CustomerId As Integer

STEP 2: Add the Silverlight Project

1) Right-click on the solution and select Add | New Project.

2) Select Silverlight | Silverlight Application.

Be sure to select the template under Visual Basic for VB applications or the template under Visual C# for C# applications.

3) Check Enable WCF RIA Services.

Be sure to check the WCF RIA Services checkbox as shown below.

image

When you add a Silverlight project, Visual Studio creates both a Silverlight project and a Web (ASP.NET) project. The ASP.NET project is crucial because:

  • It provides the startup code to start up your Silverlight project.
  • It provides the WCF service "behind the scenes" to communicate between your Silverlight application and your business objects.

NOTE: If you already have a Silverlight project, you can still enable WCF RIA Services by accessing the Silverlight project properties and defining the WCF RIA Services link as shown below.

image

STEP 3: Set a reference in the ASP.NET project to your business layer component.

Select the ASP.NET project. Then add a reference to your business layer component.

image

The solution for this post has both the C# and VB components. If you are working through this example in your language of choice, you should only have one business layer component project on this list.

By setting this reference, the ASP.NET project code can call your business layer.

STEP 4: Add a Domain Service Class

Add a domain service class to the ASP.NET application. This is the class that calls your business layer methods.

The class must be in the ASP.NET application and not the Silverlight application because you cannot define a direct reference between your Silverlight application and a standard class library project. This makes sense because the Silverlight application runs in the client browser and the ASP.NET application runs on the server where it can access your business layer component.

To add a domain service class, right-click on the ASP.NET application and select Add | New Item. Then pick the Domain Service Class template.

image

This is where this example varies greatly from an Entity Framework example. If you are using Entity Framework, you will get the list of entities here and can set some entity attributes. If you are using your own business objects, you don’t have anything shown in the Entities grid. That’s fine. Just click OK.

Since you are building your own Domain Service Class, Visual Studio will inherit your Domain Service class from DomainService. If you were building the class using Entity Framework, the class would instead inherit from LinqToEntitiesDomainService.

In most cases, you will build one Domain Service Class for each business class that you want to access from your Silverlight project.

STEP 5: Add a Query method to the Domain Service class

The query method in the Domain Service class will in turn call the Retrieve method in the business layer component.

In C#:

namespace ACM.SilverlightCSharp.Web
{
    using System.Collections.Generic;
    using System.ServiceModel.DomainServices.Hosting;
    using System.ServiceModel.DomainServices.Server;
    using ACM.BLCSharp;

    [EnableClientAccess()]
    public class CustomerDomainService : DomainService
    {

        public IEnumerable<Customer> GetCustomers()
        {
            Customer cust = new Customer();
            return cust.Retrieve();
        }

    }
}

In VB:

Imports System.ServiceModel.DomainServices.Hosting
Imports System.ServiceModel.DomainServices.Server
Imports ACM.BLVB

<EnableClientAccess()> _
Public Class CustomerDomainService
    Inherits DomainService

    Public Function GetCustomers() As IEnumerable(Of Customer)
        Dim cust As New Customer
        Return cust.Retrieve
    End Function

End Class

A few notes about this GetCustomers method:

  • It must be a method and not a property.
  • Must return one of the following:
    • A single entity
    • An IEnumerable<T> where T is the entity
    • An IQueryable<T> where T is the entity
  • Can have any parameters.
  • Can have any name.
  • Can (but does not have to) have a Query attribute to define the method as a query.

WCF RIA Services recognizes the method as a query method because of its return value. Therefore, the return value must specify the entity either by returning it or returning an IEnumerable or IQueryable of the entity.

If you build at this point and view all files in your Silverlight project, you will see a Generated_Code folder containing a *.g.cs file. This contains the code generated by Visual Studio and defines the following classes:

  • Entity class (Customer in this example): This class is generated from the business layer and includes all of the entity’s properties.
  • Domain Context class (CustomerDomainContext in this example): This class makes the WCF service calls to the Domain Service class in the ASP.NET project.

In addition, the generated code creates a service contract for the ASP.NET Domain Service class.

[For more information on the generated code, see this post.]

Step 6: Build the UI

Again, keeping with the goal of staying as simple as possible, the UI in this example is a data grid.

1) Open the designer for MainPage.xaml by double-clicking on the file.

2) Open the Data Sources window (Data | Show Data Sources).

Visual Studio automatically added the defined domain context class to your data sources:

image

Simply drag and drop the Customer data source onto the designer and Visual Studio creates the user interface for you:

image

STEP 7: Run

If you run the application, you should get this:

image

This works because when you drag and drop the data source onto the page, Visual Studio defines a DomainDataSource control and a DataGrid control on the page. It sets the DomainDataSource QueryName property to "GetCustomersQuery" and sets the DataGrid ItemsSource property to the DomainDataSource. This causes the code to call your GetCustomers method and use the results to populate the grid.

NOTE: The generated code appends the "Query" suffix to your method name in the domain context class (CustomerDomainContext). That is the method that is called from the UI, which in turn calls the GetCustomers method that you created in the domain service class (CustomerDomainService), which in turn calls the Retrieve method in your business layer via a WCF service.

So your Silverlight application is calling your business layer using the ASP.NET application as a WCF service. Here it is in picture form:

 image

To add a feature to update your data, see this post.

For a more complete example, download the extended source from here.

If you want to learn more about using Silverlight and RIA Services, come and see my talk at VSLive in Redmond Washington August 4, 2010. See this post for more information.

Use these techniques as a starting point when accessing your server-side business layer from a Silverlight application.

Enjoy!

19 Comments

  1.   Sridhar — July 19, 2010 @ 2:40 pm    Reply

    You lived up to your words, Really good Example. Will check the blog regularly for more simple examples.

    Good Work.

  2.   Paul M — August 5, 2010 @ 3:21 pm    Reply

    I think I teared up a little when I read this. Truly great article Deborah, you boiled it down to the essence and I learned more in 5 minutes than I have in a long time. Thank you so much.

  3.   Annette — August 6, 2010 @ 7:27 am    Reply

    Thank you very much for a very good and easily understandable example to get a grip on RIA Services!!

  4.   Jack — August 13, 2010 @ 4:48 am    Reply

    Thank you for the great article!
    I’m very new to Silverlight and RIA.
    How do I auto-generate the MetadataType classes? (e.g. Customer.cs)

  5.   Mrunal — August 16, 2010 @ 11:37 am    Reply

    Deborah,
    Really good post and your blog is very helpful with its focus on the basics and simplicity. Please keep blogging and really look forward for further posts on basics of technology 🙂

  6.   Ian — September 9, 2010 @ 1:30 pm    Reply

    Really great post. Most of other post make it tied with Entity Framework. POCO is still important.
    Thanks

  7.   Ian — September 9, 2010 @ 1:31 pm    Reply

    POCO is still important.
    Great post. Thanks.

  8.   UR — December 13, 2010 @ 12:48 pm    Reply

    Very, very thx for that example !!!!
    It’s the best starting point i’ve found (searching days and days).
    First it’s not with EF (not everybody has the chance to work with, i maybe will not 😉 )

    AND it’s clear, simply and not like others you can do this, this, and this – at the end ?!§$§”

  9.   Nicolas — December 14, 2010 @ 3:08 am    Reply

    Hi Deborah, i search a good POCO example since 3 month and found examples which made me think, ria and POCO is a mistery but it must be the way (vs. traditional wcf services) for pure POCO and domain driven design.

    I finally choose the WCF Data Services way and lost the idea to use DDD with Silverlight and Business Logic server side.

    You got me. From far, it’s the best example, more, it’s the only complete reference to DDD.

    One question, why do you your POCO objects implement the INotifyPropertyChanged, as the generated object inherits Entity that implements INotifyPropertyChanged ?

    Last question, what would be your repositories approach ?

    Kind regards,

    Nicolas

  10.   DeborahK — December 15, 2010 @ 12:03 am    Reply

    Hi Nicolas –
    Glad the post was helpful.

    To answer your question about why I implemented INotifyPropertyChanged in my POCO objects … my scenario was that I had existing business objects that supported my WinForms application. I then needed to add a Silverlight user interface.

    So the short answer is that the WinForms project uses binding that needs INotifyPropertyChanged.

    Hope this helps.

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