The Problem Solver

Tell me and I will forget
Show me and I will remember
Involve me and I will understand
- Confucius -

Google Ads

This Blog

Syndication

Search

Tags

News





  • View Maurice De Beijer's profile on LinkedIn

Community

Email Notifications

Explore

Archives

Consuming an ADO.NET Data Service from Silverlight

When developing Silverlight line of business (LOB) applications we often need to get at some data from a database. There are various ways to do so. One option that is easy to get started with with is creating an ADO.NET Entity Data Model (EDM) and exposing that entity model using an ADO.NET Data Service.

 

Getting started

The first thing we need to create is an ASP.NET Web Application. This is basically going to act as a container for our Data Service and our Silverlight LOB application. As you can see below I named the Web Application SLDataService.

image

Next we need to add the ADO.NET Entity Data Model. I already have a Northwind SQL Server database on my machine and that is the database I am going to expose to I am naming the EDM Northwind.edmx.

image

When the popup ask if I want to create a new EDM based on an existing database or start from scratch I selected the existing database option and pointed it at my Northwind database. This lets me select the tables I want to import. In this case I am only interested in the Customers table so that is what I am importing. By default the class name will be the same as the table name, i.e. Customers, but as Customer is  a more logical name I removed the training “s”.

image

Next step is creating the ADO.NET Data Service to publish the entity model. Add another item to the project, this time choosing an ADO.NET Data Service and naming it Northwind.svc.

image

If we open the Northwind.svc.cs file we need to enter a few details before we can proceed. The first thing we need to enter is EDM class name we are going to expose. In this case that is the NorthwindEntities model. Next we need to allow callers to access the EDM. By default nothing is exposed to this is a crucial step that needs to be done in the InitializeService() function! In this case I am going to allow everything, maybe not the best solution in real live Smile

public class Northwind : DataService<NorthwindEntities>
{
    public static void InitializeService(IDataServiceConfiguration config)
    {
        config.SetEntitySetAccessRule("*", EntitySetRights.All);
    }
}

Testing our data service

Now we should be able to test our ADO.NET Data Service in the browser. Start the project and you should see the following in the browser.

image

Navigate to the following URL http://localhost:4163/Northwind.svc/CustomerSet by adding CustomerSet and you should see the following customer data.

image

If you see an RSS feed instead of the XML go into settings and disable the feed reading view. BTW the reason the customers data is showing up as an RSS feed is because the ADO.NET Data Services uses the ATOM feed format to transmit its data using a REST approach.

image

 

Creating a Silverlight LOB client

The next step is to create a Silverlight client application to consume and display the data. Add a new project the solution of type Silverlight Application and name it SilverlightClient.

image

When prompted just accept the defaults and add the Silverlight application to the existing SLDataService app. Next we need to add a service reference to the Northwind ADO.NET Data Service. Call it NorthwindService.

Next we need to set up a bit of a user interface to display the list of customers. I kept this really simple and used a ListBox with a DataTemplate like this:

<UserControl x:Class="SilverlightClient.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Width="500" Height="300">
    <Grid x:Name="LayoutRoot" Background="White">
        <ListBox x:Name="lstCustomers">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="{Binding CompanyName}" Width="250" />
                        <TextBlock Text="{Binding City}" Width="100" />
                        <TextBlock Text="{Binding Country}" Width="100" />
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</UserControl>

 

The final step is to load the data from the service and bind this to the ListBox. To do that we need to create an DataServiceContext object of type NorthwindEntities. Unlike a regular service reference the DataServiceContext does not know its own URL by default and we need to be given the URL where the web service is located. Easy enough using the URL of the current page, loaded using HtmlPage.Document.DocumentUri, and the name of the service, Northwind.svc in this case.

Uri uri = new Uri(HtmlPage.Document.DocumentUri, "Northwind.svc");
NorthwindEntities context = new NorthwindEntities(uri);

Using this context object we can do a LINQ query to load some data. Pretty standard stuff except that the asynchronous nature of Silverlight changes the actual loading of the data a bit. Normally you would expect to do something like:

var query = from cust in context.CustomerSet 
            select cust;

lstCustomers.ItemsSource = query.ToList();

In this case that won’t work and will only result in an System.NotSupportedException with the following message "Specified method is not supported.".

The correct way of doing this is by using a DataServiceQuery object which can load the data asynchronously as follows:

var query = from cust in context.CustomerSet 
            select cust;

var dsQuery = (DataServiceQuery<Customer>)query;
dsQuery.BeginExecute(
    result => lstCustomers.ItemsSource = dsQuery.EndExecute(result), 
    null);

And the final result looks like this

image

 

Not bad at all Smile

The complete code behind looks like this:

using System;
using System.Data.Services.Client;
using System.Linq;
using System.Windows;
using System.Windows.Browser;
using System.Windows.Controls;
using SilverlightClient.NorthwindService;

namespace SilverlightClient
{
    public partial class Page : UserControl
    {
        public Page()
        {
            InitializeComponent();
            Loaded += new RoutedEventHandler(Page_Loaded);
        }

        void Page_Loaded(object sender, RoutedEventArgs e)
        {
            Uri uri = new Uri(HtmlPage.Document.DocumentUri, "Northwind.svc");
            NorthwindEntities context = new NorthwindEntities(uri);
 
            var query = from cust in context.CustomerSet 
                        select cust;

            // This doesn't work and will throw an System.NotSupportedException!
            // lstCustomers.ItemsSource = query.ToList();

            var dsQuery = (DataServiceQuery<Customer>)query;
            dsQuery.BeginExecute(
                result => lstCustomers.ItemsSource = dsQuery.EndExecute(result), 
                null);
        }
    }
}

Visual Studio project sampe code

Enjoy!

www.TheProblemSolver.nl
Wiki.WindowsWorkflowFoundation.eu

Published Tue, Jan 6 2009 13:02 by Maurice

Comments

# re: Consuming an ADO.NET Data Service from Silverlight@ Wednesday, January 28, 2009 3:35 PM

Great post Maurice. Is there any way to use a lambda also in VB code for asynchronous operations handling?

I tried but it seems that we cannot use the = operator

Thanks!

# re: Consuming an ADO.NET Data Service from Silverlight@ Wednesday, January 28, 2009 4:00 PM

@Alessandro

I am afraid that doesn't work in VB as you can only use single statements that return something. You will need to use a separate function and pass the dsQuery as the parameter.

by Maurice

# Getting started with the repository pattern in Silverlight@ Wednesday, February 18, 2009 11:03 AM

The repository pattern is quite a common design pattern when working with databases. And for a good reason

# re: Consuming an ADO.NET Data Service from Silverlight@ Thursday, February 19, 2009 4:13 AM

Did you try to secure this code?

I'm lookin for a possibility to call the Data Service in Silverlight only for an login user.

Thanks

by Marian

# re: Consuming an ADO.NET Data Service from Silverlight@ Tuesday, March 10, 2009 6:42 AM

thank you soooooooo much

by someone

# re: Consuming an ADO.NET Data Service from Silverlight@ Monday, March 16, 2009 10:10 AM

How can I secure ADO.net ds with ASP.net authentication service?

by Gabriel Rosenberg

# re: Consuming an ADO.NET Data Service from Silverlight@ Tuesday, March 17, 2009 1:18 PM

Thanks for this example.  I have a question that I'm struggling with:

When assembling an Entity for storage I need to get a related value from a lookup file.  For example a person has a status code assigned of 'Pending' which is in a table called StatusCodes.

In the Entity Framework, I need to set the value of person.StatusCode equal to an instance of the StatusCode.  In the Entity Framework or in LINQ2Sql I'd so something like this:

 var person = Person.CreatePerson( stuff );

 var statCode = myContext.StatusCodeSet.Where(sc => sc.Description == "Pending").FirstOrDefault();

 person.StatusCode = statCode;

 // ...more code here...

 myContext.BeginSaveChanges(SaveChangesOptions.Batch,

                               new AsyncCallback(OnSaveAllComplete),

                               null);

As you mentioned the query for the statCode won't work.  

However,

var person = Person.CreatePerson( stuff );

var query = from stat in myContext.StatusCodeSet

            where stat.Description == "Pending"

            select stat;

var dsQuery = (DataServiceQuery<StatusCode>)query;

dsQuery.BeginExecute(

    result => tutorApplication.StatusCode = dsQuery.EndExecute(result).FirstOrDefault(), null);

 // ...more code here...

myContext.BeginSaveChanges(SaveChangesOptions.Batch,

                          new AsyncCallback(OnSaveAllComplete),

                          null);

doesn't work either due to the Async nature of the query.  

Do you have a suggestion about how to handle this situation?

Thanks

by Lou Gallo

# re: Consuming an ADO.NET Data Service from Silverlight@ Thursday, March 19, 2009 10:13 PM

No data is retrieved. I'm using VWD Express 2008

with SSMS 2008.

How do I turn off the RSS feeds ? Can you include a copy of the Northwind.mdf for this sample ?

I'm getting a version error.

Thanks    

by Danny

# re: Consuming an ADO.NET Data Service from Silverlight@ Sunday, April 19, 2009 7:56 PM

Hi!

ADO.NET Data Services returns this message:

"Internet Explorer cannot display this feed.

The size of this feed exceeds the download limit."

Maybe because I'am accessing a large data.

How can I resolve this?

Thanks.

by Mike P

# re: Consuming an ADO.NET Data Service from Silverlight@ Monday, April 27, 2009 11:04 PM

if there are more number of records in a table the select query is throwing an exception (i think the buffer size needs to be increased as in WCF service) can any any one know the solution.

by Hareen

# re: Consuming an ADO.NET Data Service from Silverlight@ Wednesday, May 27, 2009 7:14 AM

www.silverlightitalia.com/.../accesso-ai-dati-silverlight-2.aspx

by huhauhauhauhauhauhauh

# re: Consuming an ADO.NET Data Service from Silverlight@ Friday, May 29, 2009 2:35 PM

How do you this going in vb? I got where the first commenter did.

by Jonathan

# Using ADO.NET Data Servics in Silverlight 3 and eager loading parent entities@ Wednesday, August 19, 2009 2:31 AM

Using ADO.NET Data Servics in Silverlight 3 and eager loading parent entities

# Using ADO.NET Data Servics in Silverlight 3 and eager loading parent entities@ Wednesday, July 07, 2010 2:54 PM

Using ADO.NET Data Servics in Silverlight 3 and eager loading parent entities