Getting started with the .NET RIA Services

Maurice de Beijer

Download the code

As was to be expected there were lots of announcements around Silverlight at the last MIX conference in Las Vegas. One particular product announcement is very interesting for Line Of Business (LOB) application developers. This big announcement is all about the .NET RIA Services.

What are .NET RIA Services?

RIA, short for Rich Internet Applications, is a bit of an umbrella term for all sorts of applications delivered through the browser. The key aspect however is that they deliver some business function and are not just about flashy graphics. Business applications tend to work with data and other business resources so they are usually built in the standard N tier architecture. If we take a look at this N tier architecture for the most common type of business resource, the database, we typically see the Create, Read, Update, Delete, (CRUD) pattern appear all the time. While implementing the CRUD pattern in Silverlight isn’t extremely difficult the very fact that the Silverlight application runs in the browser without direct database access and all server communication is done asynchronously makes this harder than it needs to be. This is exactly one of the problems the .NET RIA Services is trying to solve. Of course there is more to the .NET RIA Services and the standard CRUD operations is just one of the issues addressed. As we will see in this article it addresses much more by including things like data validation, general communication, keeping client and server code synchronized and more.

When evaluating the .NET RIA Services we should be looking at it from two different perspectives. First of all it is a set of design guidelines of how to create a RIA style application. Secondly it is a series of .NET libraries and Visual Studio templates implementing the design guidelines. So even if you don’t want to use the .NET RIA Services binaries, studying the design is very useful for a Silverlight line-of-business (LOB) developer. Another thing to keep in mind when evaluating the .NET RIA Services is that it is not just about Silverlight but more general. The first samples may be with Silverlight clients but a client could equally well be written in ASP.NET/JavaScript, WPF or any other client that can call WCF services.

Some of the problems the .NET RIA Services tries to solve

When developing Silverlight LOB style applications developers today are faced with a number of challenges not directly related to the business problem they are trying to solve. Some of the problems a Silverlight RIA developer faces include:

  • Both the server and client side logic need to be developed together but both are very separate from each other. Often when the server side code has been updated the developer must manually update the WCF service reference so the client side code is aware of the changes.
  • It is not possible, at least without some trickery, to use an assembly both in a regular .NET and a Silverlight assembly, making it hard to share code between the client and the server.
  • Using WCF to communicate to the server. The asynchronous nature of WCF, or all external communication for that matter, when used inside of Silverlight is an extra complicating factor.
  • Data entered needs to be validated both on the client, for immediate UI feedback, and again on the server, for security purposes.
  • The server has to be secured to prevent unauthorized use by other than the intended client application.

All of these are common problems but really not related to the actual business problem we are trying to solve. The .NET RIA Services tries to solve these problems for us making it easier to develop LOB applications in Silverlight.

Some of the techniques the .NET RIA Services uses to solve these problems.

  • The .NET RIA Services lets us work in such a way that the server and client parts of our application are two sides of one single application. This means we are not working in a Service Oriented Application (SOA) style with a very disconnected application. Instead the .NET RIA Services sees both parts of the application as one that just happens to be split into parts by the network.
  • Automatic, compile time, code generation is used to connect the client with the server parts of the application. No need to manually set a service reference or update it.
  • By using file naming conventions code written in the server part of the application can automatically be inserted into the client part of the application. Again no need for the developer to do anything except use a simple naming convention.
  • Most of the WCF communication is completely hidden from the developer and for the most part there is no need to worry about the fact that all communication is asynchronous.
  • Data validation rules are added to the entity classes in the server part of the code. These are automatically added to the client part and evaluated in both parts of the application.
  • The standard simple declarative security model we are all already familiar with can be used.

The main thing to remember when evaluating the .NET RIA Services is that it is not intended for SOA style applications where the service and the client are very loosely coupled. Where it is intended to be used is where the client and service are tightly coupled; just like in desktop client/server applications, only in this case the client and server parts of the application are separated by an internet or intranet connection.

Installing the .NET RIA Services

Before we can start doing anything with the .NET RIA Services we first need to install the library and Visual Studio templates. The installer for the .NET RIA Services can be found here: https://go.microsoft.com/fwlink/?LinkId=144609. However as the .NET RIA Services build on top of Silverlight 3 we first need to install the current Silverlight 3 beta on our machine. Please keep in mind that all of this is beta quality software and that Silverlight 3 and Silverlight 2 don’t support side by side installation so you may not want to install this on your main development machine. The Silverlight 3 beta downloads can be found here: https://silverlight.net/getstarted/silverlight3/default.aspx.

Note: If you want to install Silverlight 2 and 3 side by side Amy Dullard has created a useful guide and batch file on how to do this. You can read all about it here: https://blogs.msdn.com/amyd/archive/2009/03/18/switching-from-silverlight-3-tools-to-silverlight-2-tools.aspx

Comparing a Silverlight 2 style LOB application to a .NET RIA Services application

The best way to understand the way a .NET RIA Services application solves some of the problems we had when developing a regular Silverlight 2 style LOB application. To demonstrate this I will use both approaches to show a list of customers from the SQL Server Northwind sample database using LINQ to SQL as the data access layer. The sample I am using is deliberately very simple so as to focus on the .NET RIA Services and not be distracted by other issues. Let’s first create the regular Silverlight application and see what we need to do.

Building the standard Silverlight application.

When building the standard Silverlight application we need to perform the following steps:

  1. Create a new Silverlight Application project.
  2. Add a LINQ to SQL item to the Web project.
  3. Add the Customers table to the LINQ to SQL designer.
  4. Add a Silverlight enabled WCF Service to the Web project.
  5. Add a GetCustomers function to the service class returning all customers.
  6. Compile the Web project.
  7. Add a service reference in the Silverlight project to the just created WCF service.
  8. Add a ListBox to the MainPage to display the customer data.
  9. Create a GetCustomersCompleted handler setting the page DataContext.
  10. In the Loaded event we need to create a WCF proxy object to the WCF service.
  11. Set the event handler for the GetCustomersLoaded event.
  12. And finally we need to call the GetCustomersAsync method to load the actual data.

Image 1: The standard Silverlight application.

Private Sub MainPageLoaded() Handles Me.Loaded
    Dim proxy = New NorthwindServiceClient()
    AddHandler proxy.GetCustomersCompleted, _
        AddressOf GetCustomersCompletedHandler
    proxy.GetCustomersAsync()
End Sub
Private Sub GetCustomersCompletedHandler( _
        ByVal sender As Object, _
        ByVal e As GetCustomersCompletedEventArgs)
    DataContext = e.Result
End Sub

Listing 1: The code required to populate the ListBox with a WCF application.

Building the .NET RIA Services application.

When building the equivalent .NET RIA Services application we need to take the following steps:

  1. Create a new Silverlight Navigation Application
  2. Add a LINQ to SQL item to the Web project.
  3. Add the Customers table to the LINQ to SQL designer.
  4. Add a “Domain Service Class” to the Web project selecting the Customer LINQ to SQL entity named NorthWindService.
  5. Compile the Web project.
  6. Add a ListBox to the HomePage to display the customer data.
  7. In the HomePage Loaded event create a new NorthwindContext object.
  8. Set the page DataContext.
  9. Call the LoadCustomers method.

Image 2: Our first .NET RIA Services application.

The thing to note is that using the .NET RIA Services there are not only fewer steps to accomplish the same task but the steps left out are all about WCF and its asynchronous nature, something we don’t want to worry about when developing RIA applications. Additionally when we start adding functionality to the NorthWindService this functionality automatically shows up in the client NorthwindContext, all we need to do is compile, no longer do we need to update the service reference.

Private Sub HomePageLoaded() Handles Me.Loaded
    Dim ctx As New NorthwindContext
    DataContext = ctx.Customers
    ctx.LoadCustomers()
End Sub

Listing 2: The code required to populate the ListBox with a .NET RIA Services application.

<ListBox ItemsSource="{Binding}"
         Height="300">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal" >
                <TextBlock Text="{Binding CompanyName}"
                           Width="250" />
                <TextBlock Text="{Binding ContactName}" />
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

Listing 3: The XAML ListBox used in both samples.

.NET RIA Services communications

In the previous example we clearly had our Silverlight client communicate with our web service. But as we never added a WCF Service reference how does this actually work? The “magic” comes in two parts. The first part was the “Link to ASP.NET server project” checkbox that was enabled by default when we created the new .NET RIA Services project. Enabling this creates a stronger coupling between the Silverlight client and Web server project by allowing code generation. If you disabled this link when creating the project you can later enable it at the bottom of the Silverlight tab in the project settings.

The second part is the fact that the NorthwindService “Domain Service Class” we added is decorated with the EnableClientAccess attribute. Compiling the Web Server project will generate the Silverlight client side counterpart of this NorthwindService class. This is the NorthwindContext class we used in our Silverlight client application. If we want to take a close look at the code that was generated for us in the client project we need to click the “Show All Files” button in the Silverlight project. Once we do this we will see a folder named Generated_Code. In the sample project this folder contains a single file called LOBUsingRiaServices.Web.g.vb. Inside this file we can find the generated code for the Customer type and the NorthwindContext class as well as a NorthwindContextEntityContainer class. I will go more in-depth into the communication and code generation in a future article.

Working with different data sources

In the sample above I used LINQ to SQL to retrieve data from the database. Using LINQ to SQL is easy so I like using it to get started, but it is by no means a requirement. Out of the box the .NET RIA Services support both LINQ to SQL and the Entity Framework. All “Domain Service Class” types ultimately derive from the class DomainService and it is possible to derive from this base class and return any enumeration of objects to the Silverlight client application so this is fully extensible.

The user interface in the Silverlight Navigation Application

As you might have noticed both when adding the ListBox to the HomePage and when running the Silverlight application the Silverlight Navigation Application provides us with a default user interface to get started with. This new project template is part of Silverlight 3 and can be used in any Silverlight 3 application, not just when using the .NET RIA Services. In the previous example we just added our data to the HomePage but we can do better and use some of the new features to enhance our application.

Image 3: The customer DataGrid in the browser.

The first thing to note is that the left top of the main page contains menu items that let us navigate to child pages. These child pages are all user controls and by default stored in the Views folder. When the application first loads the HomePage.xaml is loaded and displayed. This is done inside the Frame control. The menu at the top consists of styled buttons. Another interesting feature, again not .NET RIA Services specific, is the fact that the URL in the browser changes. This allows us to bookmark individual pages and navigate directly to them.

<UserControl x:Class="LOBUsingRIAServices.CustomerListPage"
             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:web="clr-namespace:LOBUsingRIAServices.Web"
             xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml">
    <Grid x:Name="LayoutRoot" Background="White">
        <data:DataGrid ItemsSource="{Binding}"
                       IsReadOnly="True">
        </data:DataGrid>
    </Grid>
</UserControl>

Listing 4: The CustomerListPage XAML.

Creating our own view page to display the customer list is quite easy. The first step is to create a Silverlight User Control in the Views folder and call it CustomerListPage. Drag a DataGrid control from the Toolbox into the page and data bind the ItemsSource to the DataContext and set IsReadOnly to true. Add the code we used before to load the Customers to the CustomerListPageLoaded event as shown in listing 5.

Private Sub CustomerListPageLoaded() Handles Me.Loaded
    Dim ctx As New NorthwindContext
    DataContext = ctx.Customers
    ctx.LoadCustomers()
End Sub

Listing 5: The CustomerListPageLoaded event handler.

With the CustomerListPage control in place all we need to do is add a menu item to let the user navigate to our new page. This is very easy to do, just go to the MainPage.xaml and copy one of the menu buttons changing its Tag to point to our new CustomerListPage.xaml file and change the content to “customers”. When we now run the Silverlight application we will see the extra menu option appear and when we click it we will see a grid appear and, after a brief pause when the data is loaded, the customers will show up.

Adding a DomainDataSource to load the customers

So far we have still been using a few lines of code to load the customer’s collection from the server.  The .NET RIA Services also includes a DomainDataSource control so we can load the data declaratively from our XAML.  The first thing we need to do is add a reference to the System.Windows.Ria.Controls assembly. Next we can add the DomainDataSource to the CustomerListPage and tell it to use the NorthwindContext type and the LoadCustomers method to do the data loading for us. Next we need to change the DataGrid ItemsSource binding to point to the Data property of the DomainDataSource, this is done using element binding, another cool new Silverlight 3 feature. In this simple example using the DomainDataSource was actually more work than just using code. However it also enables features like paging, sorting and filtering. I will cover these DomainDataSource features in the next article.

<UserControl x:Class="LOBUsingRIAServices.CustomerListPage"
             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:web="clr-namespace:LOBUsingRIAServices.Web"
             xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml">
    <Grid x:Name="LayoutRoot" Background="White">
        <riaControls:DomainDataSource x:Name="CustomerDataSource"
                                      LoadMethodName="LoadCustomers">
            <riaControls:DomainDataSource.DomainContext>
                <web:NorthwindContext />
            </riaControls:DomainDataSource.DomainContext>
        </riaControls:DomainDataSource>
        <data:DataGrid ItemsSource="{Binding Data, ElementName=CustomerDataSource}"
                       IsReadOnly="True"
                       MouseLeftButtonUp="DataGrid_MouseLeftButtonUp">
        </data:DataGrid>
    </Grid>
</UserControl>

Listing 6: The CustomerListPage using a DomainDataSource control.

Adding a customer edit page

Adding another page to let us edit the selected customer is quite easy to do. In this sample I am going to use the new ChildWindow control that was added to Silverlight 3. The first step is to create another Silverlight User Control and call it CustomerEditPage. Drag a DataForm control from the toolbox onto this form. The DataForm control is a new control that lets us quickly create edit forms. In this case the only property we need to change is to data bind the CurrentItem to the DataContext.

Image 4: The default customer edit form.

<UserControl x:Class="LOBUsingRIAServices.CustomerEditPage"
             xmlns:dataControls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.DataForm"
             xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml">
    <Grid x:Name="LayoutRoot" Background="White">
        <dataControls:DataForm CurrentItem="{Binding}">
        </dataControls:DataForm>
    </Grid>
</UserControl>

Listing 7: The customer edit page XAML.

Next we need to add an event to the DataGrid in the CustomersListPage to activate the child window. As the DataGrid does not have a Click event the best place to do so is by adding a MouseLeftButtonUp event handler. In this event handler we can now create a ChildWindow, set its DataContext and add the previously created CustomerEditPage as the content. When this is done all we need to to do is call the Show method to display the popup.

Private Sub DataGrid_MouseLeftButtonUp( _
        ByVal sender As System.Object, _
        ByVal e As System.Windows.Input.MouseButtonEventArgs)
    Dim dataGrid As DataGrid = CType(sender, DataGrid)
    Dim editWindow As New ChildWindow
    editWindow.DataContext = dataGrid.SelectedItem
    editWindow.Content = New CustomerEditPage()
    editWindow.Show()
End Sub

Listing 8: The code required to open the child edit window.

Even though we have not specified which fields to display, both in the DataGrid and the DataForm all Customer properties show up in alphabetical order and we can edit all fields. There are several ways to control this behavior depending on the level of control we want. In a next article I will go into more details about how to do so.

Conclusion

Even though I have hardly touched the surface of the .NET RIA Services capabilities it is already obvious that using this library should make life a lot easier for the average Silverlight RIA developer. Depending on your needs you can use one of the data services supported out of the box or create your own. In the next article I will dive deeper into the .NET RIA Services and take a look at how code generation works, how we can add validation to our classes and secure our application so that not everyone can access it.

About Maurice de Beijer

Maurice de Beijer is an independent software consultant and DevelopMentor instructor specializing in Silverlight, Windows Communication Foundation, Workflow Foundation and .NET in general. He has been awarded the yearly Microsoft Most Valuable Professional award since 2005. Besides developing software Maurice also runs the user experience section of the Software Development Network, the largest Dutch .NET user group. Maurice can be reached through his website, www.TheProblemSolver.nl, or by emailing him at Maurice@TheProblemSolver.nl.