Monday, December 20, 2010

WCF Data Services

Introduction

WCF technology provides several types of services sharing the same undelying infrastructure and we can choose the appropriate service type based on our needs:



In this post, I would like to make a quick overview of WCF Data Services.

According to MSDN, WCF Data Services (formerly known as "ADO.NET Data Services") is a component of the .NET Framework that enables you to create services that use the Open Data Protocol (OData) to expose and consume data over the Web or intranet by using the semantics of representational state transfer (REST).

The main advantage of using WCF Data Services is that it allows easy access to data from any client that supports OData.

Visual Studio makes it easy to create OData service by utilizing an ADO.NET Entity Framework data model.

The following example is based on WCF Data Service Quickstart and built with Visual Studio 2010.

WCF Data Services Quick Start

The example is divided into four steps:
  1. Creating a simple ASP.NET application
  2. Defining a data model based on the well-known Northwind database by using the Entity Framework 4
  3. Adding the data service to to the web application
  4. Creating a WPF client that consumes the service
Let's start with the ASP.NET application:

File--->Project--->ASP.NET Web Application

Name it NorthwindService.

Next step is creating the corresponding data model:

Right-click the name of the ASP.NET project--->Add New Item--->ADO.NET Entity Data Model

For the name of the data model, type Northwind.edmx

Third step is creating the data service:

Right-click the name of the ASP.NET project--->Add New Item--->WCF Data Service

For the name of the service, type Northwind

After completing of these three steps, your project might look like this:



In order to enable access to our data service, we need to grant rights to the particular enities within the model:


public static void InitializeService(DataServiceConfiguration config)
{
config.SetEntitySetAccessRule("Orders", EntitySetRights.AllRead
| EntitySetRights.WriteMerge
| EntitySetRights.WriteReplace);

config.SetEntitySetAccessRule("Order_Details", EntitySetRights.AllRead
| EntitySetRights.AllWrite);

config.SetEntitySetAccessRule("Customers", EntitySetRights.AllRead);

}


Our final step will be creating a simple WPF client for consuming and modifying the model data:

In Solution Explorer, right-click the solution,
click Add--->New Project--->WPF Application.

Enter NorthwindClient for the project name.
Replace the existing code in MainWindow.xaml with this code:


<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Northwind Orders" Height="335" Width="425"
Name="OrdersWindow" Loaded="Window1_Loaded">
<Grid Name="orderItemsGrid">
<ComboBox DisplayMemberPath="OrderID" ItemsSource="{Binding}"
IsSynchronizedWithCurrentItem="true"
Height="23" Margin="92,12,198,0" Name="comboBoxOrder" VerticalAlignment="Top"/>
<DataGrid ItemsSource="{Binding Path=Order_Details}"
CanUserAddRows="False" CanUserDeleteRows="False"
Name="orderItemsDataGrid" Margin="34,46,34,50"
AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Product" Binding="{Binding ProductID, Mode=OneWay}" />
<DataGridTextColumn Header="Quantity" Binding="{Binding Quantity, Mode=TwoWay}" />
<DataGridTextColumn Header="Price" Binding="{Binding UnitPrice, Mode=TwoWay}" />
<DataGridTextColumn Header="Discount" Binding="{Binding Discount, Mode=TwoWay}" />
</DataGrid.Columns>
</DataGrid>
<Label Height="28" Margin="34,12,0,0" Name="orderLabel" VerticalAlignment="Top"
HorizontalAlignment="Left" Width="65">Order:</Label>
<StackPanel Name="Buttons" Orientation="Horizontal" HorizontalAlignment="Right"
Height="40" Margin="0,257,22,0">
<Button Height="23" HorizontalAlignment="Right" Margin="0,0,12,12"
Name="buttonSave" VerticalAlignment="Bottom" Width="75"
Click="buttonSaveChanges_Click">Save Changes
</Button>
<Button Height="23" Margin="0,0,12,12"
Name="buttonClose" VerticalAlignment="Bottom" Width="75"
Click="buttonClose_Click">Close</Button>
</StackPanel>
</Grid>
</Window>

It will give the following look to our client:



We need to add a data service reference to the client project:

Right-Click the project--->Add Reference--->Discover
In the Namespace text box, type Northwind

The only thing left is to to access the service data and we're done.
Copy this code into MainWindow.xaml.cs:



private NorthwindEntities context;
private string customerId = "ALFKI";

// Replace the host server and port number with the values
// for the test server hosting your Northwind data service instance.
private Uri svcUri = new Uri("http://localhost:12345/Northwind.svc");

private void Window1_Loaded(object sender, RoutedEventArgs e)
{
try
{
// Instantiate the DataServiceContext.
context = new NorthwindEntities(svcUri);

// Define a LINQ query that returns Orders and
// Order_Details for a specific customer.
var ordersQuery = from o in context.Orders.Expand("Order_Details")
where o.Customer.CustomerID == customerId
select o;

// Create an DataServiceCollection<t> based on
// execution of the LINQ query for Orders.
DataServiceCollection&lorder> customerOrders = new
DataServiceCollection&lorder>(ordersQuery);

// Make the DataServiceCollection<> the binding source for the Grid.
this.orderItemsGrid.DataContext = customerOrders;
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}

private void buttonSaveChanges_Click(object sender, RoutedEventArgs e)
{
try
{
// Save changes made to objects tracked by the context.
context.SaveChanges();
}
catch (DataServiceRequestException ex)
{
MessageBox.Show(ex.ToString());

}
}
private void buttonClose_Click(object sender, RoutedEventArgs e)
{
this.Close();
}



Now we can build and run the application.

As you can see, exposing and consuming a model data with WCF data services is a straightforward process, but that's not the issue, the more important thing that our WPF client can be easily replaced by other clients located in a totally different environment with no change of the service itself.

The runnable code for this tutorial could be downloaded here.

This is it,

Mark..

4 comments:

  1. Hi Mark

    The post is very nice & clear.

    What I was wondering is in what kind of app
    you think this type of solution is suited?

    Different clients in this case would be not just moving the business layer to the client side (aaarrg...), but also a duplicated layer.

    Maybe if the remoting between between
    the BL & DAL is reqired?

    What do you think?

    ReplyDelete
  2. The main advantage of using REST services (such WCF Data Services) over a regular WCF services is that information is exchanged in a pure XML or JSON formats which are much more lightweight than SOAP messages, thus less data is transferred during service calls. Using XML makes it also platform-independent.
    In addition, using such services does not require installing additional software on the clients since it relies on standard HTTP methods.
    It may be very good option to access data from Silverlight clients.

    ReplyDelete
  3. The answer is: "They work especially well when you do not know in advance who the clients might be."

    taken from Anti-Patterns To Avoid In N-Tier Applications

    ReplyDelete
  4. Hi, Mark!

    I’m the web editor at iMasters, one of the largest developer communities in Brazil. I´d like to talk to you about republishing your article at our site.

    Can you contact me at rina.noronha@imasters.com.br?

    Bests,
    Rina Noronha
    Journalist – web editor
    www.imasters.com.br
    redacao@imasters.com.br
    rina.noronha@imasters.com.br
    +55 27 3327-0320 / +55 27 9973-0700

    ReplyDelete