More Complex Operations in ADO.NET Data Services
Published: 30 Nov 2009
In this article, Sergey describes how to define custom user operations in ADO.NET Data Services or Astoria. These operations can return plain content or a collection of objects. The article examines this aspect with the help of relevant code snippets. Sergey provides a brief overview of the data model instance control and delves deep into Service operations. Towards the end of the article, Sergey points out the various data representation formats, which Astoria returns when a web service is executed.
by Sergey Zwezdin
Average Rating: This article has not yet been rated.
Views (Total / Last 10 Days): 29169/ 60


ADO.NET Data Services platform is a powerful tool to build services based on REST approach. Such services allow to work with data via HTTP conveniently. In platform ADO.NET Data Services there is a lot of implemented functional capabilities that could be used in service-oriented applications. For example, access to separate entities and fields is available out of a box. Also it is possible to perform filtration, sorting and splitting into pages operations on a server side.

All these opportunities are included in structure of ADO.NET Data Services by default and don't demand additional setting. However, in some situations there is a need to realize more flexible settings of a service work and change its behavior a little. Besides there are some situations when usual accesses to collections isn't enough and it is necessary to implement more complex logic. In this article you can read about the way to implement non-standard operations in web services, information about fine-tune of web services based on ADO.NET Data Services platform.

Data Model Instance Control

When you build a service based on ADO.NET Data Services platform you should specify a data model that will be used as a parent for a creating web service. For REST-service a data model is an essential component because a web service gives access to these data.

A data model is defined in a generic-parameter of DataService<> base class. In this case when you access to a service infrastructure, ADO.NET Data Services instances a data model automatically and works with it. As a result, a default constructor is used without any parameters.

Listing 1 - Simple web service

public class WebDataService1 : DataService<NorthwindEntities>

If a data model doesn't have a constructor without parameters, infrastructure of ADO.NET Data Services can't create any instance of this type. It is the reason you'll get an error message when try to access to such service. This situation is well-spread. That's why many developers prefer to avoid default constructors.

To resolve this problem you should override a way to instantiate a data model and use a necessary constructor of a data model. You should override CreateDataSource method to get own algorithm of instantiate of a data model. As result, this method returns a type that is specified in a generic-parameter of a base class at a web service definition. By default this method accesses to CreateDataSource method of a base class which tries to find a default constructor and create an object.

Listing 2 - The definition of instance mode of data model

protected override NorthwindEntities CreateDataSource()
  return base.CreateDataSource();

If a correct work of a web service demands of redefine logic of a data model creation then you need to build a model manually and use a suitable constructor. Also in this method it is possible to use a reference to IoC-container or implement based on Dependency Injection principle. In the simplest case an instance of a data model can be created and get a string of a connection with a server of databases.

Listing 3 - The definition of instance mode of data model

protected override NorthwindEntities CreateDataSource()
      return new NorthwindEntities(@"some connection string");

Thus, CreateDataSource method will be called every time when hosting-environment needs to instantiate a data model. 

Service Operations

Service operations are one of the important and powerful mechanisms of ADO.NET Data Services extension. Service operations are necessary when standard functionality of ADO.NET Data Services queries aren't enough. For example, it is impossible to perform a complex query to a database, using the light URI syntax ADO.NET Data Services. In this case it is possible to use service operations. Also service operations can be used to generate content in non-standard formats if it is necessary. For example, you can generate a HTML-code with description of a web service. Also usage of service operations makes it possible to provide access to any binary contents, for example, to images.

Implementation of difficult queries to a data model is one of most well-spread reasons to use service operations. You can build a big request, with multiple join operations, additional conditions and sorting. To implement such service operation you need to define a new method in a service. Such method should have two specific features - return IQueryable collection as a result and be marked with WebGet attribute.

Listing 4 - The definition of service operation

public IQueryable<Customers> <span style='background:white'>GetCustomersWithOrders</span>()
  return CurrentDataSource.Customers.Where(c => c.Orders.Count > 0);

In service operations it is possible to construct query of any complexity and to return its to client. For the access to service operation it is necessary to use the kind of address "http://localhost:9580/WebDataService1.svc/GetCustomersWithOrders". Also this operation will appear in service metadata. It can be checked up, having accessed to the address "http://localhost:9580/WebDataService1.svc/$metadata".

You can also use operations with parameters. It is useful when the same query is executed several times and there is a changeable parameter. To define this behavior you should specify a parameter in the method. For example, it is possible to change the previous example and specify quantity of orders.

Listing 5 - The definition of service operation with parameter

public IQueryable<Customers> GetCustomersWithCountOrders(int count)
  return CurrentDataSource.Customers.Where(c => c.Orders.Count > count);

In this case for the access to operation it is necessary to use the kind of address "http://localhost:9580/WebDataService1.svc/GetCustomersWithCountOrders?count=5".

Names of methods shouldn't be equal to collection names. As a method returns result in a form of Iqueryable so it is possible to use all opportunities of ADO.NET Data Services platform. For example, it is possible to organize paging of results of operation execution. Also you can do filtration and sorting.

WebGet method, that marks methods, means there is opportunity to advert to service operations via GET HTTP-verb. Also it is possible to provide other methods of treatment. For these purposes you should use WebInvoke attribute instead of WebGet. Specifying a value of WebInvoke attribute there is need to specify an HTTP-method to be used.

Listing 6 - The usage WebInvoke attribute

[WebInvoke(Method = "POST")]
public void SetCustomer()
  // ...

Other HTTP-methods can be used in the same way.

Except receiving collections, service operations can be used to get some individual results. For example, a service operation can help to receive a data model image. For this purpose you need to create a method which returns Stream object. This method should be marked with attributes WebGet and SingleResult. SingleResult attribute indicates that the method returns not a set of data but an individual result. Besides that, it is necessary to mark with MimeType attribute to set value of "Content-Type" HTTP-header in an HTTP-response. MimeType attribute is specified for each method separately. It accepts two parameters - a name of a method and value of HTTP-header.

Listing 7 - The usage attributes both MimeType and SingleResult

[MimeType("GetCustomerPhoto", "image/jpg")]
public class WebDataService1 : DataService<NorthwindEntities>
      public System.IO.Stream GetCustomerPhoto(string customerId)

Similarly, you can generate and send a client HTML-content or any other data. It is important to notice, that when you access to such service operations, ADO.NET Data Services packs these data into XML format.  To avoid this effect and obtain these data without distortions it is necessary to add a keyword "$value" in an address. For example, the address to service access can look like "http://localhost:9580/WebDataService1.svc/GetPhoto/$value".

Service operations, as well as containers, are also amenable to rules of safety. For this reason, we should explicitly authorize the use of service operations in InitializeService method. In IDataServiceConfiguration interface there is SetServiceOperationAccessRule method that helps to do it. To grant permission to all operations you can employ the following code.

Listing 8 - The definition of security rules

public class WebDataService1 : DataService<NorthwindEntities>
      public static void InitializeService(IDataServiceConfiguration config)
            // ...
            config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);

So, thanks to employing service operations it is possible to expand functionality of web services   based on ADO.NET Data Services platform essentially.

Data Representation Formats

By default ADO.NET Data Services web-services returns data in AtomPub format. Such representation is very convenient in most cases because it is hierarchically structured, easy readable to perceive without additional parsing. As its building is based on XML format, so a service can be used in an heterogeneous environment.

But sometimes you need to use other data formats. Nowadays ADO.NET Data Services platform supports two formats - AtomPub and JSON. JSON format is easy to use to interact with JavaScript client scenarios.

ADO.NET Data Services defines a format to response automatically. It occurs on the basis of "Accept" header in HTTP-request. If this header is empty or it contains "application/atom+xml" value then data will be displayed in AtomPub format. If the header contains "application/json" value then data will be presented in JSON form.

This is the way to choose a data format generated by ADO.NET Data Services.


ADO.NET Data Services Platform is a powerful and universal tool, which provides a large set of functionality out of a box. In most cases this functionality is enough. However, sometimes you need to solve a non-standard task. In these cases it is possible to take advantage of ideas described in the given article.

User Comments

Title: fasdfa   
Name: asdfasdf
Date: 2012-08-25 7:46:11 AM
Title: developer   
Name: developer
Date: 2011-07-31 1:24:23 PM
When I try this in new version of WCF Data Services,
public System.IO.Stream GetCustomerPhoto(string customerId)
generates an exception and says that Stream cannot be serialized and returned.
Do you know why?
Title: System.IO.Stream GetCustomerPhoto?   
Name: Dana
Date: 2010-03-11 2:46:40 PM
You can return an image from a service operation? I couldn't figure this out. Can you elaborate on that stub? When I tried to create the service operation and then "update service reference" from my client app, I got an error to the effect that the meta data couldn't be created.
Great article and any further info is appreciated. Thanks,
Title: moreclick   
Name: moreclick
Date: 2009-12-07 2:17:58 AM
Thanks for sharing, I love reading you should post more often...

Product Spotlight
Product Spotlight 

Community Advice: ASP | SQL | XML | Regular Expressions | Windows

©Copyright 1998-2021  |  Page Processed at 2021-11-26 10:49:30 PM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search