Creating and Consuming Windows Communication Foundation (WCF) Data Services

Introduction

Windows Communication Foundation (WCF) Data Services allow you to create and consume services using Open Data Protocol (OData). In the process WCF data services allow you to access your data using REpresentational State Transfer (REST). This article gives you a jump start in creating and consuming WCF data services. It also shows how queries can be executed in asynchronous manner and illustrates how paged data can be dealt with.

Overview of REST and OData

Before you begin developing a WCF data service it would be useful to quickly glance over the two key technologies that make WCF data services - REST and OData.

REST stands for REpresentational State Transfer. REST architecture makes use of existing and time proven protocol for communication instead of inventing a new one. REST style communication relies on HTTP protocol for data transfer. In other words the client application uses HTTP verbs such as GET, PUT, POST, and DELETE to communicate with server data. Thus, using REST you can perform CRUD (Create, Read, Update and Delete) operations on your data.

The Open Data Protocol (OData) is a protocol for querying and updating data belonging to your applications. OData does so by leveraging existing technologies such as REST, HTTP, ATOM and JSON. OData accesses data via URIs. In OData, you point to entity resources as an entity set that contains instances of entity types. For example, the URI http://localhost/Northwind/EmployeeService.svc/Employees returns all of the records from the Employees table. WCF Data Services framework provides client libraries for your .NET applications so that you can consume the data services using .NET Framework objects.

Creating a Data Model

Now that you have basic idea about WCF data services, let's begin creating a WCF data service (EmployeeService) that deals with employee data. For this example you will use the Employees table of Northwind sample database.

Create a new, blank ASP.NET Web Application using Visual Studio 2010. The first step in building the WCF data service is to create an Entity Framework data model. So, add a new ADO.NET Entity Data Model to your web application. Name the data model EmployeeModel.

Add a new ADO.NET Entity Data Model to your web application
Figure 1: Add a new ADO.NET Entity Data Model to your web application

Follow the wizard and select Employees table for data model creation. The following figure shows Employee entity in the designer.

The Employee entity in the designer
Figure 2: The Employee entity in the designer

Note that the Entity Container Name is NorthwindEntities, entity name is Employee and entity set name is Employees.

Creating a WCF Data Service

The next step is to add a WCF data service to the web application you previously created. Name the WCF data service EmployeeService.svc and open the data service class.

Open the data service class
Figure 3: Open the data service class

Modify the data service class as shown below:

public class EmployeeService : DataService<NorthwindEntities>

{

    public static void InitializeService(DataServiceConfiguration config)

    {

        config.SetEntitySetAccessRule("Employees", EntitySetRights.All);

        config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;

    }

}

As you can see, the EmployeeService class derives from DataService base class and you pass the type defining the data service (NorthwindEntities). The InitializeService() method initializes the data service by configuring entity access levels and other aspects of the service. For example, the above code sets the access rule for Employees entity set to All. The available entity set rules include ReadSingle, ReadMultiple, AllRead, AllWrite and All (for a complete list, please refer MSDN help for EntitySetRights enumeration). This completes our data service.

Just to ensure that the data service is working correctly, run the .svc file in the browser. Your browser window should resemble the following figure.

Run the .svc file in the browser
Figure 4: Run the .svc file in the browser

Consuming a WCF Data Service

Now that you are ready with the data service, let's create a client application that will consume the service. The client application can be a desktop application or another web application. For our example we will create an ASP.NET web application and then consume the WCF data service. So, add another ASP.NET web application to the same solution. Add a reference to the WCF data service using "Add Service Reference" dialog.

Add Service Reference
Figure 5: Add Service Reference

Click on the Discover button so that Visual Studio will find data services from the current solution. Change the namespace name if you wish and click OK. This will add a service reference to EmployeeService as shown below:

Add a service reference to EmployeeService
Figure 6: Add a service reference to EmployeeService

Open the default web form, import ServiceReference1 namespace and place a GridView control on it. Then add the following code in Page_Load event handler.

protected void Page_Load(object sender, EventArgs e)
{
    Uri svcUri=new Uri("http://localhost:1031/EmployeeService.svc");
 
    NorthwindEntities db = new NorthwindEntities(svcUri);
 
    GridView1.DataSource = db.Employees;
    GridView1.DataBind();
}

The code creates an instance of Uri class by passing the URL where the EmployeeService is located. In a more real world situation you will store this URL in the web.config file for obvious reasons. The code then instantiates NorthwindEntities and binds Employees to the GridView. If you run the web form it should resemble the following figure.

Run the web form
Figure 7: Run the web form

The Employees property used in the code above is actually a DataServiceQuery and represents a query being sent to the WCF data service. You could have also written the above code in the following way:

DataServiceQuery<Employee> query = (DataServiceQuery<Employee>)
        from emp in db.Employees
        select emp;
 
QueryOperationResponse<Employee> items = (QueryOperationResponse<Employee>)query.Execute();
 
GridView1.DataSource = items;
GridView1.DataBind();

Here you created DataServiceQuery instance explicitly and then specified a query (from...select...) that retrieves required employees (all in the above code). The Execute() method of DataServiceQuery object executes the query and returns the results as QueryOperationResponse object. The items retrieved as the response are then bound with the GridView.

Executing Queries Asynchronously

The code that you examined in the preceding section uses Execute() method to execute the query against the WCF data service. This execution is synchronous in nature. In some cases you may want to execute the queries in asynchronous fashion. To do so WCF data services follow the standard BeginXXXX and EndXXXX pattern of .NET Framework. The following code will make the usage of this pattern clear.

...
DataServiceQuery<Employee> query = (DataServiceQuery<Employee>)from emp in db.Employees
        select emp;
 
try
{
    query.BeginExecute(OnQueryComplete, query);
    System.Threading.Thread.Sleep(5000);
}
catch (DataServiceQueryException ex)
{
    throw new ApplicationException("An error occurred while executing query", ex);
}
...

Here, the DataServiceQuery instance defines the query to be executed as before. To call the query, however, you use the BeginExecute() method. The BeginExecute() method accepts a callback method that will be called after the query completion and the DataServiceQuery instance. The code deliberately puts a delay of 5 seconds for the sake of testing. The OnQueryComplete callback method looks like this:

private void OnQueryComplete(IAsyncResult result)
{
    DataServiceQuery<Employee> query = result.AsyncState as DataServiceQuery<Employee>;
    QueryOperationResponse<Employee> items = (QueryOperationResponse<Employee>)query.EndExecute(result);
    GridView1.DataSource = items;
    GridView1.DataBind();
}

The OnQueryComplete method receives IAsyncResult object as a parameter. The AsyncState property of the IAsyncResult object gives the original DataServiceQuery instance (the one on which you invoked the BeginExecute() method). We then call the EndExecute() method to complete the operation and retrieve the results as a QueryOperationResponse. The response is bound with the GridView as in the previous case.

Executing Paged Queries

In the above examples, executing a query returned all the Employee entities in the response. If your query is dealing with a large number of entities you may want to restrict the number of entities returned at a time in the response. Luckily, WCF data services allow you to page the data returned from the queries. By default, paging is disabled but you can enable it in the InitializeService() method as shown below:

public static void InitializeService(DataServiceConfiguration config)
{
    ...
    config.SetEntitySetPageSize("Employees", 3);
    ...
}

The SetEntitySetPageSize() method allows you to set the page size of an entity set. Setting page size will cause only the specified number of items to be returned in the response at a time. Further items can be retrieved as and when required. The following code fragment illustrates how multiple pages can be retrieved in the client application using the technique just mentioned.

Uri svcUri=new Uri("http://localhost:1031/EmployeeService.svc");
 
NorthwindEntities db = new NorthwindEntities(svcUri);
DataServiceQueryContinuation<Employee> pageFlag = null;
DataServiceQuery<Employee> query = (DataServiceQuery<Employee>)from emp in db.Employees
        select emp;
QueryOperationResponse<Employee> items = (QueryOperationResponse<Employee>)query.Execute();
do
{
    if (pageFlag != null)
    {
        items = db.Execute<Employee>(pageFlag) as QueryOperationResponse<Employee>;
        Response.Write("<hr>");
    }
 
    foreach (Employee emp in items)
    {
        Response.Write(emp.FirstName + " " + emp.LastName + "<br>");
    }
}
while ((pageFlag = items.GetContinuation()) != null);

The code declares an instance of DataServiceQueryContinuation class. The DataServiceQueryContinuation class encapsulates a URI that returns the next page of a paged query result. When you call the Execute() method on the DataServiceQuery object it will return only 3 records since we have configured the page size to be 3. A do...while loop iterates through the returned items and outputs them on the response stream. Notice the while condition. We call the GetContinuation() method that returns an instance of DataServiceQueryContinuation (if applicable). Accordingly we output <HR> element to indicate a page of data. The following figure shows a sample run of the web form:

A sample run of the web form
Figure 8: A sample run of the web form

Modifying Data from Client Application

For the sake of completeness let's add some code in the client application that allows us to update and delete employees. This code goes primarily in the RowUpdating and RowDeleting event handlers of the GridView control. Have a look at the following code fragments:

protected void GridView1_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
    ...
    var query = (from emp in db.Employees
                where emp.EmployeeID == Convert.ToInt32(e.Keys[0])
                select emp).Single();
    query.FirstName = e.NewValues[0].ToString();
    query.LastName = e.NewValues[1].ToString();
    db.UpdateObject(query);
    db.SaveChanges();
    ...
}
protected void GridView1_RowDeleting(object sender, GridViewDeleteEventArgs e)
{
    ...
    var query = (from emp in db.Employees
                    where emp.EmployeeID == Convert.ToInt32(e.Keys[0])
                    select emp).Single();
 
    db.DeleteObject(query);
    db.SaveChanges();
    ...
}

The RowUpdating event handler performs the update operation on the data service. It does so by first filtering the employee to be modified and then calling the UpdateObject() method with the modified Employee instance. The SaveChanges() method actually persists the changes to the database. Similarly, the RowDeleting event handler uses DeleteObject() method to delete an Employee from the database.

Though the above example doesn't insert any new employees, doing so is easy as illustrated below:

Employee emp = new Employee();
emp.FirstName = "Tom";
emp.LastName = "Jerry";
db.AddToEmployees(emp);
db.SaveChanges();

The above code creates a new Employee entity instance and sets its properties. The Employee is then added to the entity set using the AddToEmployees() method.

Summary

WCF data services make use of REST style communication coupled with OData protocol. They allow you to expose data over a network that can be manipulated using HTTP verbs such as GET, PUT, POST and DELETE. WCF data services make the development easy by leveraging Entity Framework data models. WCF data services also provide client libraries that allow object based access to the underlying data service.



About the Author

Bipin Joshi

Bipin Joshi is a blogger and writes about apparently unrelated topics - Yoga & technology! A former Software Consultant by profession, Bipin has been programming since 1995 and has been working with the .NET framework ever since its inception. He has authored or co-authored half a dozen books and numerous articles on .NET technologies. He has also penned a few books on Yoga. He was a well known technology author, trainer and an active member of Microsoft developer community before he decided to take a backseat from the mainstream IT circle and dedicate himself completely to spiritual path. Having embraced Yoga way of life he now codes for fun and writes on his blogs. He can also be reached there.

Related Articles

Comments

  • WCF Data Service VS 2010 Installed Templates

    Posted by NonYa on 11/27/2012 01:36pm

    its there... ...add a WCF data service to the web application you previously created... Add new item -Web-WCF Data Service

    Reply
  • No WCF Data Service Template

    Posted by wsyeager on 10/03/2011 03:50pm

    There is no Project template called "WCF Data Services". I have VS2010 SP1 and looked via the Extensions manager as well.
    
    If there is, please let me know.
    
    In addition, I am able to create and use a WCF Service Application to pass data retrieved from and inserted into Entities.
    To do this, I do the following:
    - Create a [DataContract(IsReference = true)] attribute on the Data Contract.
    - Set LazyLoading = False for the EF Model.
    - Set the DbContext.Configuration.ProxyCreationEnabled = false in the method call.
    - Turn on EagerLoading by using the "Include" statement for a method that uses multiple relationships between entities.

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • On-demand Event Event Date: September 10, 2014 Modern mobile applications connect systems-of-engagement (mobile apps) with systems-of-record (traditional IT) to deliver new and innovative business value. But the lifecycle for development of mobile apps is also new and different. Emerging trends in mobile development call for faster delivery of incremental features, coupled with feedback from the users of the app "in the wild." This loop of continuous delivery and continuous feedback is how the best mobile …

  • Webinar on September 23, 2014, 2 p.m. ET / 11 a.m. PT Mobile commerce presents an array of opportunities for any business -- from connecting with your customers through mobile apps to enriching operations with mobile enterprise solutions. Join guest speaker, Michael Facemire, Forrester Research, Inc. Principal Analyst, as he discusses the new demands of mobile engagement and how application program interfaces (APIs) play a crucial role. Check out this upcoming webinar to learn about the new set of …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds