Printer Friendly Version      Send     
Click to Rate and Give Feedback
MSDN
MSDN Library
Visual Studio 2008
Technical Articles
 Using Microsoft ADO.NET Data Servic...
Using Microsoft ADO.NET Data Services

Microsoft Data Platform Development Technical Article

Mike Flasko

Microsoft® Corporation

Published: August 2008

Applies To:

  • ADO.NET Data Services
  • Visual Studio 2008 SP1
  • .NET Framework 3.5 SP1

Summary: This document describes how to create and use Microsoft® ADO.NET Data Services, and discusses various details around the URI and payload formats. This document is meant as an introduction to ADO.NET Data Services and thus covers the core aspects of the technology, defering discussion of more advanced topics to companion documents.

Introduction:

The goal of Microsoft® ADO.NET Data Services is to enable applications to expose data as a data service that can be consumed by web clients within corporate networks and across the internet. A data service is reachable via regular HTTP requests, using standard HTTP verbs such as GET, POST, PUT and DELETE to perform CRUD operations against the service. The payload format used by the service is controllable by the application, but all options are simple, open formats such as JSON and Atom/APP.

The use of web-friendly technologies make ADO.NET Data Services ideal as a data back-end for AJAX-style applications, Rich Interactive Applications and other applications that need to operate against data that is stored across the web.

Getting Started: Creating Data Services

Pre-requisites

In order to create a data service using ADO.NET Data Services in your own environment you will need Microsoft Visual Studio 2008 SP1. If you will be using your data service to access data stored in a relational database, you will also need a database with updated data-access providers, such as Microsoft SQL Server 2005 or 2008 (any edition, including SQL Server Express, will work). Updated providers are also available for third party database such as Oracle and DB2. For more information on third party providers see http://msdn.microsoft.com/data.

The ADO.NET Entity Framework runtime and associated tools are included in Visual Studio 2008 SP1.

Selecting a Data Source

The ADO.NET Data Service server framework is comprised of two halves. The top-half is the runtime itself; this part is “fixed”, and it implements URI translation, the Atom/JSON wire formats, the interaction protocol, etc. This is what makes an ADO.NET Data Service look like an ADO.NET Data Service. The bottom half is the data-access layer and is pluggable. Communication between layers happens in terms of the IQueryable interface plus a set of conventions to map CLR graphs into the URI/payload patterns of ADO.NET Data Services.

The first step in creating an ADO.NET Data Service is to determine the data source that is to be exposed as a set of REST-based endpoints (ie. select or create a data access layer).  For relational data stored in Microsoft SQL Server or other 3rd Party databases, ADO.NET Data Services currently enables easily exposing a conceptual model created using the ADO.NET Entity Framework (EF).  For all other data sources (XML document, web service, application logic layer, etc) or to use additional database access technologies (ex. LINQ to SQL), a mechanism is provided which enables any data source, as per the plug-in model described above, to be exposed as an ADO.NET Data Service. 

To create a data service which exposes a relational database through an Entity Framework conceptual model see “Creating a Data Service using the ADO.NET Entity Framework”. To create a data service which exposes another data source see “Creating a Data Service from any Data Source”.          

Creating a Data Service using the ADO.NET Entity Framework

ADO.NET Data Services are a specialized form of Windows Communication Foundation services, and thus can be hosted in various environments. The below example will create an ADO.NET Data Service which is hosted inside an ASP.NET site. In order to create a data service, you must first create a web project; you will then need to establish a connection with the database that will be exposed by the service, and then create the data service itself within the web application. Below is a step-by-step description of this process.

NOTE: These steps are for Visual Studio Standard, Professional and Team System editions. If using Visual Studio Web Developer, create a new “Web Site” rather than a “Web Application”. The remaining workflow does not change. While this example uses a web application, other project types (websites) and hosting mechanisms are also supported.

  1. Create the project
    • Create a “Web Application” project by going to the File menu in Visual Studio and choosing New Project. When the New Project window appears, choose either Visual Basic or Visual C# as the programming language. Within the language category click on “Web”, and select “ASP.NET Web Application” from the right-hand panel. Choose a name for the project, for example SimpleDataService, and click OK.NOTE:
  2. Create an Entity Data Model representation of your database using the ADO.NET Entity Framework
    • Assuming that you already have a database that you want to expose as a data service, we will create an Entity Data Model schema that maps 1:1 with your database. Select SimpleDataService Add New Item in Visual Studio. The Add New Item window will appear, choose “ADO.NET Entity Data Model”, give it a name and click Add. We will use the Northwind sample database throughout this example, so we will use “Northwind” as our name (Northwind.edmx being the generated file name).
    • In the rest of the step-by-step guide we will assume you are using the Northwind sample database, so the database connection created here should point to Northwind.NOTE:
  3. Create a data service
    • To create the data service itself, select SimpleDataService Add New Item in Visual Studio. Choose “ADO.NET Data Service” from the list of item templates, give it a name (e.g. Northwind) and click add. NOTE:
    • Visual Studio will open the code file for the new service by default. You can also find the file in the Solution Explorer; it will have the name you indicated, with a “.svc.cs” or “.svc.vb” extension. Add an “imports” (Visual Basic”) or “using” (C#) clause at the beginning of the file to include the namespace of the data classes generated by the wizard in step 2.b. You can use the Visual Studio object browser to locate the name, or you can rely on intellisense. By default the namespace is derived from the database that was used for the data service, unless changed when the EDM is created, for example if the database was called Northwind the namespace will be NorthwindModel.
    • Locate the “TODO: put your data source class name here” comment that indicates to put in the class name that represents the database, and replace it with the name of the class that was generated by the Entity Data Model Wizard in step 2.b. Again, the name is derived from the database name, unless changed, so for example if the database is called “Northwind” the class will be “NorthwindEntities”.
  4. Enable access to the data service
    • By default a data service does not expose any resources.For security purposes, access to resources needs to be explicitly enabled before any resources or associations are accessible. To enable read and write access to all resources in the Entity Data Model associated with the service; locate the InitializeService method as shown in Example 1 below.

The code file (e.g. northwind.svc.cs) should look more or less like the example below.

C#
using System;
using System.Web;
using System.Collections.Generic;
using System.ServiceModel.Web;
using System.Linq;
using System.Data.Services;
using NorthwindModel;
namespace SimpleDataService
{
    public class Northwind : DataService<NorthwindEntities>
    {
        public static void InitializeService(IDataServiceConfiguration                                                            config)
        {
            config.SetEntitySetAccessRule("*", EntitySetRights.All);
        }
    }
}

Example 1: Basic data service in C#

To test the data service, simply hit Ctrl+F5 within Visual Studio, which will start the development web server and will run the Data Services server inside it. See the “Trying an ADO.NET Data Service” section below to walk through a trial run of your newly created data service.

Creating a data service from any data source

In general, ADO.NET Data Services work by converting a request to perform an operation over a resource, identified by a URI, to the equivalent operation on the data model it represents.  When the data model is backed by a relational database, URIs are converted to Entity Framework Object Services method calls (as per the section ‘Creating a local data service using the ADO.NET Entity Framework’ above).  Since that approach is specific to the Entity Framework, a different method is required when the underlying data model is backed by a data source other than a relational database (XML Document, web service, etc).  In this case, requests to URIs are converted to LINQ queries.  To enable this approach, ADO.NET Data Services maps objects implementing the IQueryable interface in a CLR object graph to Entity Sets.  This approach enables the ADO.NET Data Services Framework to expose any data source which has an IQueryable provider written for it.  In order to enable such layering (ADO.NET Data Services over IQueryable-based data sources) a mapping is defined between CLR objects and artifacts of the EDM-based data model used by the ADO.NET Data Services Framework.   

The remainder of this section defines by example the mapping between CLR constructs and artifacts of an EDM-based data model.  How to define classes implementing the IQueryable interface such that they are represented as Entity Sets in the service is shown below; however, IQueryable implementation specifics will be covered in a separate document.

NOTE: The steps below walk through creating an ADO.NET Data Service based on a CLR object graph. These steps produce a data service created over an in memory collection of objects. This approach is done as a simple way to show how an arbitrary CLR graph can be exposed as a service and is handy for mocking data sources. In a typical production deployment, the IQueryable properties shown representing Entity Sets would not expose in memory data, but rather would translate the IQueryable expression trees to data source specific queries.

  1. Create the project
    • Create a “Web Application” project by going to the File menu in Visual Studio and choosing New Project. When the New Project window appears, choose either Visual Basic or Visual C# as the programming language, and within the language category click on “Web”, and select “ASP.NET Web Application” from the right-hand panel. Choose a name for the project, for example CustomDataService, and click OK.NOTE:
      1. Create a data service
    • To create the data service itself, select CustomDataService Add New Item in Visual Studio. Choose “ADO.NET Data Service” from the list of item templates, give it a name (e.g. contacts) and click add. NOTE: 
    • Copy & paste the code from Example 2 into the code file opened in step 2.b.
    • In the CustomDataService namespace you should now have a class called ‘ContactsData’ which has two public properties (Contacts & Users) which return IQueryable<Contact> and IQueryable<User>.These properties represent Entity Sets in the CLR model.The User and Contact classes in turn define the base Entity Types for each of the Entity Sets.
      1. Enable access to the data service
    • By default a data service does not expose any resources.For security purposes, access to resources needs to be explicitly enabled before any resources or associations are accessible. To enable read and write access to all resources in the Entity Data Model associated with the service, locate the InitializeService method and ensure it matches what is shown in Example 2 below.
      1. Try the data service
    • Press F5 to run the project and navigate to /contacts.svc.This returns the root document for the service.Navigating to /contacts.svc/Users will return all users.
    • See the ‘Trying an ADO.NET Data Service’ section below

C#
using System;
using System.Collections.Generic;
using System.Data.Services;
using System.Linq;
namespace CustomDataService
{
    public class User
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public IList<Contact> Contacts{get; set;}
    }
    public class Contact
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public string Email { get; set; }
    }
    public class ContactsData : //IUpdatable
    {
        #region Populate Service Data
        static User[] _users;
        static Contact[] _contacts;
        static ContactsData()
        {
            _users = new User[]{
              new User(){ ID=0, Name="Mike",Contacts= new List<Contact>()},
              new User(){ ID=1, Name="Saaid",Contacts= new List<Contact>()},
              new User(){ ID=2, Name="John",Contacts= new List<Contact>()},
              new User(){ ID=3, Name="Pablo",Contacts= newList<Contact>()}};
            _contacts = new Contact[]{
              new Contact(){ ID=0, Name="Mike", Email="mike@contoso.com" },
              new Contact(){ ID=1, Name="Saaid", Email="Saaid@hotmail.com"},
              new Contact(){ ID=2, Name="John", Email="j123@live.com"},
              new Contact(){ ID=3, Name="Pablo", Email="Pablo@mail.com"}};
            _users[0].Contacts.Add(_contacts[0]);
            _users[0].Contacts.Add(_contacts[1]);
            _users[1].Contacts.Add(_contacts[2]);
            _users[1].Contacts.Add(_contacts[3]);
        }
        #endregion
        public IQueryable<User> Users
        {
            get { return _users.AsQueryable<User>(); }
        }
        public IQueryable<Contact> Contacts
        {
            get { throw new DataServiceException(403, "Requests directly to
                                               /Contacts are not allowed");}
        }
    public class contacts : DataService<ContactsData>
    {
        // This method is called only once to initialize
        //service-wide policies.
        public static void InitializeService(IDataServiceConfiguration
                                             config)
        {
            config.SetEntitySetAccessRule("*", EntitySetRights.All);
        }
       //Service operations, query interceptors & change interceptors go here
    }
}

Example 2: ADO.NET Data Service exposing an in-memory data source

Trying an ADO.NET Data Service

The easiest way to test your ADO.NET Data Service is to simply access it with a web browser. While this is probably not the way you will ultimately use the data service (it is more likely that a program will interact with it), it is an easy way to understand how requests work, what results look like, and other details surrounding the implementation of the service.

To interact with the data service, open a web browser such as Microsoft Internet Explorer and point it to the URL that is the entry point to the site. If you created the data service locally using Visual Studio, you can simply hit Ctrl+F5 to start the web server, and then point the URL in the browser that Visual Studio launches to the data service file. For example, “http://host/vdir/northwind.svc” where “host” is a computer name or localhost; you may also need to add a port number.

NOTE: To view Atom (the default format returned by an ADO.NET Data Service) in Internet Explorer, you must first ensure that Feed Reading View is turned off. This can be done on the Content tab of Tools | Internet Options.

When you hit the entry point, (after setting the Entity Set access rules as per the examples above) the response is an XML response that contains the list of Entity Sets exposed by the data service.  Since the default serialization used by a data service is Atom, the document returned by default is an Atom service document (as shown in the examples below).  If you are using the full Northwind sample database, the output will be similar to what is shown in Example 3 below.  

<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
  <service xml:base="http://localhost:51905/nw.svc/" xmlns:atom=http://www.w3.org/2005/Atom xmlns:app="http://www.w3.org/2007/app" xmlns="http://www.w3.org/2007/app">
   <workspace>
     <atom:title>Default</atom:title>
     <collection href="Categories">
       <atom:title>Categories</atom:title>
     </collection>
     <collection href="CustomerDemographics">
       <atom:title>CustomerDemographics</atom:title>
     </collection>
     <collection href="Customers">
       <atom:title>Customers</atom:title>
     </collection>
     <collection href="Employees">
       <atom:title>Employees</atom:title>
     </collection>
     <collection href="Order_Details">
       <atom:title>Order_Details</atom:title>
     </collection>
     <collection href="Orders">
       <atom:title>Orders</atom:title>
     </collection>
     <collection href="Products">
       <atom:title>Products</atom:title>
     </collection>
     <collection href="Region">
       <atom:title>Region</atom:title>
     </collection>
     <collection href="Shippers">
       <atom:title>Shippers</atom:title>   
     </collection>
     <collection href="Suppliers">
       <atom:title>Suppliers</atom:title>
     </collection>
     <collection href="Territories">
       <atom:title>Territories</atom:title>
     </collection>
  </workspace>
</service>

Example 3: Response for the root of a data service

Using this as a starting point, you can start to browse the contents of the data service. To continue with the Northwind example, you can add “/Products” to the URL, resulting in “http://host/northwind.svc/Products”, which returns all of the products in the store. Example 4 below shows a partial listing of the result.

<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<feed xml:base="http://host/northwind.svc/" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservicesdataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservicesdataservices/metadata" xmlns="http://www.w3.org/2005/Atom">
  <id>http://host/northwind.svc/Products</id>
  <updated />
  <title type=”text”>Products</title>
  <link rel="self" href="Products" title="Products" />
  <entry>
    <id>http://host/northwind.svc/Products(1)</id>
    <updated />
    <title />
    <author>
      <name />
    </author>
    <link rel="edit" href="Products(1)" title="Products" />
    <category term="NorthwindModel.Products"
      scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" /> 
    <content type="application/xml">
      <m:properties>
        <d:ProductID m:type="Edm.Int32">1</d:ProductID>
        <d:ProductName>Chai</d:ProductName>
        <d:QuantityPerUnit>10 boxes x 20 bags</d:QuantityPerUnit>
        <d:UnitPrice m:type="Edm.Decimal">18.0000</d:UnitPrice>
        <d:UnitsInStock m:type="Edm.Int16">39</d:UnitsInStock>
        <d:UnitsOnOrder m:type="Edm.Int16">0</d:UnitsOnOrder>
        <d:ReorderLevel m:type="Edm.Int16">10</d:ReorderLevel>
        <d:Discontinued m:type="Edm.Boolean">false</d:Discontinued>

      </m:properties>
    </content>
    <link
   rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Categories" 
   title="Categories" href="Products(1)/Categories"
   type="application/atom+xml;type=entry" />
    <link
rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Order_Details" title="Order_Details" href="Products(1)/Order_Details"
   type="application/atom+xml;type=feed" />
    <link
rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Suppliers" title="Suppliers" href="Products(1)/Suppliers"
            type="application/atom+xml;type=entry" />
  </entry>
  <entry> … </entry>
</feed>

Example 4: Listing of the contents of an entity set, in Atom/APP format

If you want to construct a URL that points to a particular entity, such as a particular Product in this example, you can do so by adding the key value in parenthesis (the URL of a given entity can be obtained by composing the name of the entity instance element, and the base URL of the XML document). For example, the URL “http://host/northwind.svc/Products(1)” would produce the results shown in Example 5 below.

<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<entry xml:base="http://localhost:63952/northwind.svc/" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom">
  <id>http://localhost:63952/northwind.svc/Products(1)</id>
  <title type="text" />
  <updated>2008-06-24T01:30:30Z</updated>
  <author>
    <name />
  </author>
  <link rel="edit" title="Products" href="Products(1)" />
  <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Categories" type="application/atom+xml;type=entry" title="Categories" href="Products(1)/Categories" />
  <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Order_Details" type="application/atom+xml;type=feed" title="Order_Details" href="Products(1)/Order_Details" />
  <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Suppliers" type="application/atom+xml;type=entry" title="Suppliers" href="Products(1)/Suppliers" />
  <category term="NorthwindModel.Products"
      scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
  <content type="application/xml">
    <m:properties>
      <d:ProductID m:type="Edm.Int32">1</d:ProductID>
      <d:ProductName>Chai</d:ProductName>
      <d:QuantityPerUnit>10 boxes x 20 bags</d:QuantityPerUnit>
      <d:UnitPrice m:type="Edm.Decimal">18.0000</d:UnitPrice>
      <d:UnitsInStock m:type="Edm.Int16">39</d:UnitsInStock>
      <d:UnitsOnOrder m:type="Edm.Int16">0</d:UnitsOnOrder>
      <d:ReorderLevel m:type="Edm.Int16">10</d:ReorderLevel>
      <d:Discontinued m:type="Edm.Boolean">false</d:Discontinued>
    </m:properties>
  </content>
</entry>

Example 5: Response for a single-entity URL

If you look at the values of the properties on the entity in Example 5, you will notice that some of them such as ProductName and UnitPrice are scalar values, where as others such as Categories and Suppliers are different (they are part of a link element). The latter ones represent “navigation properties”, properties that navigate from an entity (Product in this case) to a related entity (the product’s category or its supplier in this case). URLs can be composed to traverse this relationship. For example, to see the supplier for this product we would use:

http://host/northwind.svc/Products(1)/Suppliers

In this section, we have gone through a quick overview of how to create and interact with data services. Please see the additional sections for a deeper look at ADO.NET Data Services.

Finding and Pointing to Data: URLs in Data Services

ADO.NET Data Services defines a simple, yet very expressive, URL format that allows applications to point to sets of entities and individual entities, as well as to traverse relationships between entities. Several options can also be added as query string parameters to control how the data is presented.

Structure of Web Data Services URLs

The basic format for URLs is:

http://host/<service>/<EntitySet>[(<Key>)[/<NavigationProperty>[(<Key>)/...]]]

NOTE: In the syntax above, [ ] imply optional components

The 3 main elements of the URL syntax are:

  1. The data service URI.The data service URI is the first part of the URL that points to the root of the data service.This will typically be (but is not limited to) a .svc file. For example, http://host/myapp/northwind.svc. The examples below assume that the URLs start with that prefix for brevity.
  2. The entity-set name (optional).If you include an entity-set name, then all the entities in that entity-set are returned. For example, /Customers would return all of the customers in the Northwind data service. The system also allows for an optional filter predicate contained in parenthesis to subset the response to a single entity.For single-key entities, you can simply indicate the key value, and the resulting URL will point to that entity specifically. For example, if there is a customer entity with a string-based key ‘ALFKI’, its URL would be /Customers(‘ALFKI’).Additional expression-based filtering on a set is enabled by using query string parameters, which are described later in this document
  3. A navigation property (optional).A navigation property can be placed after the entity-set name (separated by a “/”), indicating that you want to traverse the relationship being pointed to. For example, /Customers(‘ALFKI’)/Orders would return the sales orders of the customer with the primary key ‘ALFKI’. Similar to the entity set name, a filter can also be applied to the navigation property using query string operators (described later in this document) to return only a subset of the related entities. For example, /Customers(‘ALFKI’)/Orders?$filter=OrderDate gt '1998-1-1' returns all the orders posted after Jan 1st, 1998, for the customer with a key ‘ALFKI’. Since the result of traversing a relationship through a navigation property is another set of entities, you can continue to add navigation properties to the URL to navigate through the relationship graph specified in the data service schema. For example, /Customers(‘ALFKI’)/Orders(1)/Employees returns the employees that created sales order 1 for the customer with a key of ‘ALFKI’.

Query string options

While the URL format allows for filtering and traversing through the graph of entities in the store, it does not have constructs to control the output. For that, a number of optional query string parameters are supported by ADO.NET Data Services. Table 1 below lists all of the query options along with their description and some usage examples.

Option Description Example

expand

The ‘expand’ option allows you to embed one or more sets of related entities in the results. For example, if you want to display a customer and its sales orders, you could execute two requests, one for /Customers(‘ALFKI’) and one for /Customers(‘ALFKI’)/Orders. The ‘expand’ option on the other hand allows you to return the related entities in-line with the response of the parent in a single HTTP request.

You may specify multiple navigation properties to expand by separating them with commas, and you may traverse more than one relationship by using a dot to jump to the next navigation property.

--a customer with related sales orders
/Customers(‘ALFKI’)?$expand=Orders

--a customer with related sales orders and employee information related to those orders
/Customers(‘ALFKI’)?$expand=Orders/Employees

--Orders with related employees information and related shipper information
/Orders(10248)?$expand=Employees,Shippers

orderby

Sort the results by the criteria given in this value. Multiple properties can be indicated by separating them with a comma. The sort order can be controlled by using the “asc” (default) and “desc” modifiers.

/Customers?$orderby=City

/Customers?$orderby=City desc

/Customers?$orderby=City desc,CompanyName asc

skip

Skip the number of rows given in this parameter when returning results. This is useful in combination with “top” to implement paging (e.g. if using 10-entity pages, saying $skip=30&top=$10 would return the fourth page). NOTE: Skip only makes sense on sorted sets; if an orderby option is included, ‘skip’ will skip entities in the order given by that option. If no orderby option is given, ‘skip’ will sort the entities by primary key and then perform the skip operation.

--return all customers except the first 10

/Customers?$skip=10

--return the 4th page, in 10-row pages

/Customers?$skip=30&$top=10

top

Restrict the maximum number of entities to be returned. This option is useful both by itself and in combination with skip, where it can be used to implement paging as discussed in the description of ‘skip’.

--top 5 sales orders

/Customers?$top=5

--top 5 sales orders with the highest TotalDue

/Orders?$orderby=TotalDue&$top=5

filter

Restrict the entities returned from a query by applying the expression specified in this operator to the entity set identified by the last segment of the URI path.

-- all customers in London

/Customers?$filter=City eq ‘London’

-- Match all Customers with the value of the property ‘fullname’ equal to ‘Wayne, John’ /Customers?$filter='Wayne, John' eq insert(ContactName, length(lastname), ',')

Table 1: Query string options

Expression Syntax

The simple expression language that is used in filter operators (and also supported in orderby operations) supports references to columns and literals. The literal values can be strings enclosed in single quotes, numbers and boolean values (true or false) or any of the additional literal representations shown in the ‘Data Type Literal Representations’ section below. The operators in the expression language use abbreviations of the names rather than symbols to reduce the amount of escaping necessary in the URL. The abbreviations are listed in Table 2.

Operator Description Example

Logical Operators

eq

Equal

/Customers?filter=City eq 'London'

ne

Not equal

/Customers?filter=City ne 'London'

gt

Greater than

/Product?$filter=UnitPrice gt 20

ge

Greater than or equal

/Orders?$filter=Freight ge 800

lt

Less than

/Orders?$filter=Freight lt 1

le

Less than or equal

/Product?$filter=UnitPrice le 20

and

Logical and

/Product?filter=UnitPrice lteq 20 and UnitPrice gt 10

or

Logical or

/Product?filter=UnitPrice lteq 20 or UnitPrice gt 10

not

Logical negation

/Orders?$ ?$filter=not endswith(ShipPostalCode,'100')

Arithmetic Operators

add

Addition

/Product?filter=UnitPrice add 5 gt 10

sub

Subtraction

/Product?filter=UnitPrice sub 5 gt 10

mul

Multiplication

/Orders?$filter=Freight mul 800 gt 2000

div

Division

/Orders?$filter=Freight div 10 eq 4

mod

Modulo

/Orders?$filter=Freight mod 10 eq 0

Grouping Operators

( )

Precedence grouping

/Product?filter=(UnitPrice sub 5) gt 10

Table 2: Operators for filter expressions

In addition to the operators described above, a set of functions are also defined for use with the filter query string operator.  The following tables list the available functions.  This release does not support Aggregate functions (sum, min, max, avg, etc) as they would change the meaning of the ‘/’ operator to allow traversal through sets.  For example, /Customers?$filter=average(Orders/Amount) gt 50.00 is not supported.  Additionally, ISNULL or COALESCE operators are not defined. Instead, there is a null literal which can be used for comparison following CLR semantics.

String Functions

bool substringof(string p0, string p1)

bool endswith(string p0, string p1)

bool startswith(string p0, string p1)

int length(string p0)

int indexof(string arg)

string insert(string p0, int pos, string p1)

string remove(string p0, int pos)

string remove(string p0, int pos, int length)

string replace(string p0, string find, string replace)

string substring(string p0, int pos)

string substring(string p0, int pos, int length)

string tolower(string p0)

string toupper(string p0)

string trim(string p0)

string concat(string p0, string p1)

Table 3: String Functions

Date Functions

int day(DateTime p0)

int hour(DateTime p0)

int minute(DateTime p0)

int month(DateTime p0)

int second(DateTime p0)

int year(DateTime p0)

Table 4: Date Functions

Math Functions

double round(double p0)

decimal round(decimal p0)

double floor(double p0)

decimal floor(decimal p0)

double ceiling(double p0)

decimal ceiling(decimal p0)

Table 5: Math Functions

Type Functions

bool IsOf(type p0)

bool IsOf(expression p0, type p1)

<p0> Cast(type p0)

<p1> Cast(expression p0, type p1)

Table 5: Type Functions

Examples

  • /Orders?$filter=ID eq 1From
    • From all the Orders in the data store, return only the Orders with the ‘ID’ property equal to 201
  • /Customers?$filter='Wayne, John' eq insert(fullname, length(lastname), ',')
    • Match all Customers with the value of the property ‘fullname’ equal to ‘Wayne, John’
  • /Customer$filter=isof(‘SpecialCustomer’)
    • Match all customers that are of type SpecialCustomer.Entity sets support inheritance and thus customer entities in the entity set may be of different types within a type hierarchy

Data Type Literal Representations

Each of the supported data types in ADO.NET Data Services has a literal form defined.  This literal form is used in URLs generated and accepted by the ADO.NET Data Services Framework to identify the data type of a literal.  The literal form of each supported data type is shown in Table 6 below.

ADO.NET Data Services Literal Form EDM Type CLR Type

null

null

null

binary‘[A-Fa-f0-9][A-Fa-f0-9]*’

X ‘[A-Fa-f0-9][A-Fa-f0-9]*’

NOTE: X is case sensitive and binary isn't. Spaces are not allowed between binary and the quoted portion. Spaces are not allowed between X and the quoted portion. Odd pairs of hex digits are not allowed.

Edm.Binary

byte[]

true | false

Edm.Boolean

Bool

[A-Fa-f0-9]+

Edm.Byte

Byte

datetime'yyyy-mm-ddThh:mm[:ss[.fffffff]]'

NOTE: Spaces are not allowed between datetime and quoted portion. datetime is case-insensitive.The format actually allows anything from the

DateTimeKind.RoundtripKind, which may preserve timezone information.

Edm.DateTime

DateTime

decimal‘[0-9]’

Edm.Decimal

Decimal

‘[0-9]+ ([.[0-9]+] | [E[+ | -][0-9]+])

Allows 1E+10

Edm.Double

Double

‘[0-9]+.[0-9]+f’

Edm.Float

float

guid‘dddddddd-dddd-dddd-dddddddddddd'

where each d represents [A-Fa-f0-9]

NOTE: guid is case insensitive and spaces are not allowed between guid and the quoted portion.

Edm.Guid

Guid

‘[0-9]+’

Edm.Int16

Int16

‘[0-9]+’

Edm.Int32

Int32

‘[0-9]+L’

Edm.Int64

Int64

‘[0-9]+’

Edm.SByte

SByte

‘[0-9]+F’

Edm.Single

Single

'char*'

NOTE: Delimiters are escaped by doubling them.

Edm.String

String

Table 6: Literal Forms for Supported Data Types

Options for Data Representation

ADO.NET Data Services currently supports exchanging entities in JSON and Atom (an XML- based feed format). In all cases, the same format can be used both to receive information from the data service as well as to send to it.

Which format is best depends largely on the nature of the application and the runtime environment being used. For example, AJAX-based applications that run inside web browsers may find the JSON format easier to use, as it can be easily turned into JavaScript objects. On the other hand, a client application may be written with a language/runtime library that has a built-in XML parser, making the Atom format would be a good choice.

The mechanism used to specify in which format information is sent to a data service is the “Content-Type” HTTP header. Following the HTTP RFC 2616, the mechanism used to control the format returned by the system is the “Accept” HTTP header.

Requested Mime Type Response Mime Type Serialization Format

Grouping Media Types

*/*

application/atom+xml

AtomPub

text/*

Not supported

N/A

application/*

Not supported

N/A

Individual Media Types

text/xml

text/xml

AtomPub

application/xml

application/xml

AtomPub

application/atom+xml

application/atom+xml

AtomPub

application/json

application/json

JSON

Table 7: Supported payload formats

Atom format details

The Atom Publishing Protocol is an HTTP-based approach for creating and editing Web resources. It is designed fundamentally around the idea of using the basic operations provided by the HTTP protocol (such as GET, PUT, POST and DELETE) to pass around instances of Atom 1.0 Feed and Entry documents that represent things like blog entries, podcasts, wiki pages, calendar entries and so on.

 

To enable Atom serialization in a data service, a fixed mapping from entities to Atom constructs is defined.  For responses from the data service, the response can be either a set or a single entity.  Entity sets are represented as <atom:feed> elements and single entities as <atom:entry> elements. For requests to the data service, see the section “Changing Data in Web Data Services” below.

Each property of an Entity is represented by an element within the <atom:content> element. The <atom:content> element is a child element of <atom:entry>.  The value of the property is included as the content of the associated element. Each <atom:entry> element has an <atom:ID> element that contains the URL to the entity. URLs are given in absolute form as per the Atom specification.  Each response also includes  an “xml:base” attribute that provides the base to resolve the relative URLs within the document. A hypothetical Customer entity for /Customers(‘ALFKI’) with no relationships is shown in Example 6.

<?xml version="1.0" ?>

<entry xmlns="http://www.w3.org/2005/Atom"

  xml:base=http://server/service.svc

  xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"

  xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">

       <title/>

       <id>http://server/service.svc/Customer(’ALFKI’)</id>

       <updated/>

      <category term="NorthwindModel.Customers"

     scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />

       <content type=”application/xml”>

        <m:properties>

              <d:CustomerID>ALFKI</d:CustomerID>

              <d:CompanyName> Alfreds Futterkiste</d:CompanyName>

              <d:Address> Obere Str. 57</d:Address>

        </m:properties>

       </content>

</entry>

Example 6: A single-entity response from the data service.

If the URL specified in the request matches more than one entity, the entities are returned inside an <atom:feed> element, as illustrated by the partial result listing for /Customers in Example 7 below.

<?xml version="1.0" encoding="utf-8" standalone="yes" ?>

<feed xml:base="http://server/service.svc/" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservicesdataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom">
  <id>http://server/service.svc/Customers</id>
  <updated />
  <title>Customers</title>
  <link rel="self" href="Customers" title="Customers" />
  <entry>
  <id>http://server/service.svc/Customers('ALFKI')</id>
  <updated />
  <title />
   <author>
  <name />
  </author>
<category term="NorthwindModel.Customers"
 scheme=http://schemas.microsoft.com/ado/2007/08/dataservices/scheme
/> 
<link rel="edit" href="Customers('ALFKI')" title="Customers" />
   <content type="application/xml">
    <m:properties>
    <d:CustomerID>ALFKI</d:CustomerID>
    <d:CompanyName>Alfreds Futterkiste</d:CompanyName>
    <d:ContactName>Maria Anders</d:ContactName>
    <d:ContactTitle>Sales Representative</d:ContactTitle>
    <d:Address>Obere Str. 57</d:Address>
    <d:City>Berlin</d:City>
    <d:Region d:null="true" />
    <d:PostalCode>12209</d:PostalCode>
    <d:Country>Germany</d:Country>
    <d:Phone>030-0074321</d:Phone>
    <d:Fax>030-0076545</d:Fax>
  <m:properties>
  </content>
  <link  
rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Orders"
     title="Orders" href="Customers('ALFKI')/Orders"
type="application/atom+xml;type=feed" />
  <link
rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/CustomerDemographics"
     title="CustomerDemographics" href="Customers('ALFKI')/CustomerDemographics" type="application/atom+xml;type=feed" />
  </entry>
   // Additional <entry> elements
</feed>

Example 7: A response that contains multiple entities.

For entities that have relationships, a navigation property is included and represented using an <atom:link rel=”http://schemas.microsoft.com/ado/2007/08/dataservices/related/[NavProp]”> element.  This element contains a URL pointing to the related entities (the related entities themselves are not included), as shown in Example 7 (Note the “Orders” navigation property).

If the request includes an option to expand one or more navigation properties, such as /Customers(‘ALFKI’)?$expand=Orders, the related entities are nested under the <atom:link rel=”related”> element representing the navigation property, as shown below in Example 8.

<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<entry xml:base="http://localhost:63952/northwind.svc/" 
     xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"   
 xmlns:m=http://schemas.microsoft.com/ado/2007/08/dataservices/metadata
xmlns="http://www.w3.org/2005/Atom">
  <id>http://localhost:63952/northwind.svc/Customers('ALFKI')</id>
  <title type="text" />
  <updated>2008-06-24T02:08:05Z</updated>
  <author>
    <name />
  </author>
  <link rel="edit" title="Customers" href="Customers('ALFKI')" />
  <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Orders" type="application/atom+xml;type=feed" title="Orders" href="Customers('ALFKI')/Orders">
    <m:inline>
      <feed>
        <title type="text">Orders</title>
 <id>http://localhost:63952/northwind.svc/Customers('ALFKI')/Orders</id>
        <updated>2008-06-24T02:08:05Z</updated>
        <link rel="self" title="Orders" href="Customers('ALFKI')/Orders"
         />
        <entry>
          <id>http://localhost:63952/northwind.svc/Orders(10643)</id>
          <title type="text" />
          <updated>2008-06-24T02:08:05Z</updated>
          <author>
            <name />
          </author>
          <link rel="edit" title="Orders" href="Orders(10643)" />
   <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Customers"
           type="application/atom+xml;type=entry"

           title="Customers" href="Orders(10643)/Customers" />
   <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Employees" type="application/atom+xml;type=entry" title="Employees" href="Orders(10643)/Employees" />
  <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Order_Details" type="application/atom+xml;type=feed" title="Order_Details" href="Orders(10643)/Order_Details" />
  <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Shippers" type="application/atom+xml;type=entry" title="Shippers" href="Orders(10643)/Shippers" />
  <category term="NorthwindModel.Orders" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
  <content type="application/xml">
    <m:properties>
      <d:OrderID m:type="Edm.Int32">10643</d:OrderID>
      <d:OrderDate m:type="Edm.DateTime">1997-08-
                   25T00:00:00</d:OrderDate>
      <d:RequiredDate m:type="Edm.DateTime">1997-09-22T00:00:00</d:RequiredDate>
      <d:ShippedDate m:type="Edm.DateTime">1997-09- 02T00:00:00</d:ShippedDate>
      <d:Freight m:type="Edm.Decimal">29.4600</d:Freight>
      <d:ShipName>Alfreds Futterkiste</d:ShipName>
      <d:ShipAddress>Obere Str. 57</d:ShipAddress>
      <d:ShipCity>Berlin</d:ShipCity>
      <d:ShipRegion m:null="true" />
      <d:ShipPostalCode>12209</d:ShipPostalCode>
      <d:ShipCountry>Germany</d:ShipCountry>
    </m:properties>
  </content>
</entry>
//Additional <entry> elements

  </feed>
 </inline>
</link> 
<category term="NorthwindModel.Customers" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
<content type="application/xml">
  <m:properties>
    <d:CustomerID>ALFKI</d:CustomerID>
    <d:CompanyName>Alfreds Futterkiste</d:CompanyName>
    <d:ContactName>Maria Anders</d:ContactName>
    <d:ContactTitle>Sales Representative</d:ContactTitle>
    <d:Address>Obere Str. 57</d:Address>
    <d:City>Berlin</d:City>
    <d:Region m:null="true" />
    <d:PostalCode>12209</d:PostalCode>
    <d:Country>Germany</d:Country>
    <d:Phone>030-0074321</d:Phone>
    <d:Fax>030-0076545</d:Fax>
  </m:properties>
     </content>
</entry>

Example 8: Response with nested related entities using the "expand" option.

In addition to the regular format for exchanging entities and the per service metadata description available from each data service, Atom defines the concept of a service document which describes all the sets available from the service.  ADO.NET Data Services will expose a service document from the URI representing the root of the service (ex. http://server/service.svc).  The service document lists the URIs representing each of the entity sets available from the data service.

<?xml version="1.0" encoding="utf-8" standalone="yes" ?>

<service xml:base="http://server/service.svc/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:app="http://www.w3.org/2007/app" xmlns="http://www.w3.org/2007/app">
<workspace>
  <atom:title>Default</atom:title>
  <collection href="Categories">
  <atom:title>Categories</atom:title>
  </collection>
  <collection href="CustomerDemographics">
  <atom:title>CustomerDemographics</atom:title>
  </collection>
  <collection href="Customers">
  <atom:title>Customers</atom:title>
  </collection>
  <collection href="Employees">
  <atom:title>Employees</atom:title>
  </collection>
   <collection href="Order_Details">
  <atom:title>Order_Details</atom:title>
  </collection>
  <collection href="Orders">
  <atom:title>Orders</atom:title>
  </collection>
  <collection href="Products">
  <atom:title>Products</atom:title>
  </collection>
  <collection href="Region">
  <atom:title>Region</atom:title>
  </collection>
  <collection href="Shippers">
  <atom:title>Shippers</atom:title>
  </collection>
  <collection href="Suppliers">
  <atom:title>Suppliers</atom:title>
  </collection>
  <collection href="Territories">
  <atom:title>Territories</atom:title>
  </collection>
  </workspace>
</service>

Example 9: Atom service document as returned from an ADO.NET Data Service.

JSON format details

The JSON format follows the data encoding described in the RFC 4627 to represent data using a subset of the JavaScript syntax. For more information on JSON see RFC 4627 in the IETF web site (http://tools.ietf.org/html/rfc4627) and the http://json.org web site.

 The JSON format in ADO.NET Data Services also uses a fixed mapping from entities. Entities themselves are mapped to a JSON object, where each property of the object represents a property of the entity. For requests, a single object is expected by the data service. For responses, arrays are returned when sets are retrieved and a single JSON object when sets are filtered by key.  To guard against Cross-Site Request Fogery (CSRF) attacks using JSON, the array or JSON object in a response is always wrapped by a single JSON object with a single member named “d” whose value includes the array or object representing the entity or entities being returned.  

In addition to the set of properties that correspond to the entity, each JSON object also includes a member called “__metadata” (double underscore prefix). This member carries metadata for each entity exchanged between the client and server. The members of the metadata object are listed in Table 6.

Member Description Applies To

Type

The name of the entity type

All entities, both top-level and nested under another entity (through the use of the “expand” option). It is not present on navigation properties that have not been expanded.

Uri

The URI (relative to base URI of the target data service) for this entity in the data service

Both entities and navigation properties. When a navigation property is not expanded, the value of the property includes a single “__deferred” (double underscore prefix) member which includes a Uri property which contains the URL that can be used to retrieve the related entities.

Table 8: Members of the "__metadata" object in JSON format

Example 10 shows the response from a data service, over the Customers entity-set in the Northwind database, for a URL that requests a single entity back (/Customers(‘ALFKI’)).

{

  "d" : {
     __metadata: {

        uri: "http://server/service.svc/Customers(\'ALFKI\')",

        type: "NorthwindModel.Customers"
     },

     CustomerID: "ALFKI",

     CompanyName: "Alfreds Futterkiste",

     ContactName: "Maria Anders",

     ContactTitle: "Sales Representative",

     Address: "Obere Str. 57",

     City: "Berlin",

     Region: null,

     PostalCode: "12209",

     Country: "Germany",

     Phone: "030-0074321",

     Fax: "030-0076545",

     Orders: {
        __deferred: {
           uri: "http://server/service.svc/Customers(\'ALFKI\')/Orders"
        }
     },

     CustomerDemographics: {
        __deferred: {
           uri: “http://server/service.svc/Customers(\'ALFKI\')/CustomerDemographics"
        }
     }
  }

}

Example 10: JSON response from a data service for a single 'Customer' entity

If more than one entity matches the criteria, the response from the data service is similar to the single-entity case shown in Example 10 above, except that an array of JSON objects is returned instead of a single object.

If the entity has navigation properties, such as Orders in Example 10, by default the value of the property is the __deferred object, which contains the URI that can be used to retrieve the related entities.

If a hierarchy is returned by the data service as a result of using the “expand” option, objects are nested in the JSON payload. This results in the proper references being created between JavaScript objects during de-serialization by the consumer of the data. Example 11 shows a Customer entity with expanded sales orders.

{

  "d" : {
     __metadata: {

        uri: "http://server/service.svc/Customers(\'ALFKI\')",

        type: "NorthwindModel.Customers"
     },

     CustomerID: "ALFKI",

     CompanyName: "Alfreds Futterkiste",

     ContactName: "Maria Anders",

     ContactTitle: "Sales Representative",

     Address: "Obere Str. 57",

     City: "Berlin",

     Region: null,

     PostalCode: "12209",

     Country: "Germany",

     Phone: "030-0074321",

     Fax: "030-0076545",

     Orders: [
        {

           __metadata: {
              uri: "http://server/service.svc/Orders(10643)",

              type: "NorthwindModel.Orders"
           },

           OrderID: 10643,

           OrderDate: "\/Date(872467200000)\/",

           RequiredDate: "\/Date(874886400000)\/",

           ShippedDate: "\/Date(873158400000)\/",

           Freight: "29.4600",

           ShipName: "Alfreds Futterkiste",

           ShipAddress: "Obere Str. 57",

           ShipCity: "Berlin",

           ShipRegion: null,

           ShipPostalCode: "12209",

           ShipCountry: "Germany",

           Customers: {
              __deferred: {
                 uri: "http://server/service.svc/Orders(10643)/Customers"
              }
           },

           Employees: {
              __deferred: {
                 uri: "http://server/service.svc/Orders(10643)/Employees"
              }
           },

           Order_Details: {
              __deferred: {
                 uri: "http://server/service.svc/Orders(10643)/Order_Details"
              }
           },

           Shippers: {
              __deferred: {
                 uri: "http://localhost:51905/nw.svc/Orders(10643)/Shippers"
              }
           }
        },

        // Additional order objects

     ]

     CustomerDemographics: {
        __deferred: {
           uri: “http://server/service.svc/Customers(\'ALFKI\')/CustomerDemographics"
        }
     }
  }

}

Example 11: A hierarchical result containing a Customer and its related Sales Orders, in JSON format.

Changing Data in ADO.NET Data Services

The data services exposed by ADO.NET Data Services not only allow you to obtain data, but also to change data in the store. Data services provide a uniform mechanism for creating, updating and deleting entities, as well as creating and deleting associations between entities.

Creating a new entity

To create a new entity, an HTTP POST request needs to be sent to the URI that points to the container for that entity. For example, for a data service created over the Northwind sample database in SQL Server, to create a new Category object you would send an HTTP POST request to the /Categories URI (e.g. http://host/vdir/northwind.svc/Categories).

The payload of the HTTP POST request is the entity data, encoded in any of the supported formats. The “Content-Type” header in the HTTP request needs to indicate the format so the data service knows how to interpret the data appropriately.  This behavior for POST requests maps to that described in the AtomPub RFC.  Not all the properties of a given entity type need to be included; those not included will take their default value in the server. If a given property is not nullable the create operation will fail. Example 12 shows the payload of a POST request to create a new category, using both the Atom and JSON formats.

ATOM:

<entry  xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"

xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"

xmlns="http://www.w3.org/2005/Atom">

  <content type="application/xml">

    <m:properties>

      <d:CategoryName>New Category</d:CategoryName>

    </m:properties>

  </content>

</entry>

JSON:

{

    CategoryName: "New Category"

}

Example 12: Payloads for creating a new Category entity using Atom and JSON

In the case of Example 12, the primary key for the entity (CategoryID property) is declared in the model to be automatically generated by the server (an IDENTITY column in SQL Server), so there is no need to specify it here. If the key property (or properties) is not generated by the server then they must also be specified in the payload.

After processing the POST request, the data service will return the entity that was created, with all of its values updated to reflect any changes that happened on the server, such as server-generated keys, properties modified at the database level using triggers, etc.  In addition to the entity returned in the payload, a ‘Location’ HTTP response header is returned that includes the URI to the newly created entity as per AtomPub RFC 5023.

ATOM:

<?xml version="1.0" encoding="utf-8" standalone="yes" ?>

<entry xml:base="http://host/ northwind.svc/" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom">

  <id>http://host/northwind.svc/Categories(11)</id>

  <updated />

  <title />

  <author>

    <name />

  </author>

  <link rel="edit" href="Categories(11)" title="Categories" />

  <category term="NorthwindModel.Categories"

    scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />

  <content type="application/xml">

   <m:properties>

    <d:CategoryID m:type="Int32">11</d:CategoryID>

    <d:CategoryName>NewCat2</d:CategoryName>

    <d:Description d:null="true" />

    <d:Picture m:type="Byte[]" d:null="true" />

   </m:properties>

  </content>

  <link

     rel="

     http://schemas.microsoft.com/ado/2007/08/dataservices/related/Products"

     title="Products" href="Categories(11)/Products"

     type="application/atom+xml;type=feed" />

</entry>

JSON:

{

  "d" : {

    __metadata: {

      uri: "http://host/northwind.svc/Categories(11)",

      type: "NorthwindModel.Categories"

    },

    CategoryID: 11,

    CategoryName: "New Category",

    Description: null,

    Picture: null,

    Products: {

      __deferred: {

        uri: "http://host/northwind.svc/Categories(11)/Products"

      }

    }

  }

}

Example 13: Response from the data service after processing a POST request for creating a Category, in Atom and JSON formats

Updating existing entities using merge semantics

There are two possible options for updating existing entities, a merge-based update or a replace-based update. An existing entity can be modified (updated) by sending an HTTP MERGE request to the URI where the entity is located. Following with the example for creating an entity, to modify the Category entity with key ‘11’ from the Northwind data service you would use the /Categories(11) URI.

In the case of merge-based updates, the payload needs to be an entity and only needs to contain the properties that are being modified. If a property is not included, the value that is currently present in the server will be preserved. Example 14 shows the payload used to update the category that was inserted in the previous example.

ATOM:

<entry xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"

    xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"

    xmlns="http://www.w3.org/2005/Atom">

  <content type="application/xml">

   <m:properties>

    <d:CategoryName>Changed Category</d:CategoryName>

   </m:properties>

  </content>

</entry>

JSON:

{

    CategoryName: "Changed Category"

}

Example 14: Payload used to modify an existing Category entity through an HTTP PUT request, Atom and JSON formats

The response from HTTP MERGE requests is a 204 (No Content) HTTP response.  In future versions, we may consider enabling responses similar to that returned from POST requests where the response payload is the latest version of the entity.

Updating existing entities using replace semantics

An existing entity can be modified (updated) by sending an HTTP PUT request to the URL where the entity is located. Following with the example for creating an entity using a POST, to modify the Category entity with key ‘11’ from the Northwind data service you would use the /Categories(11) URI.

In the case of replace-based updates, the payload needs to be an entity and should contain all the properties of the entity (not including navigation properties). If a property is not included, the value is reset on the server to the default value for the property.  This behavior for PUT requests maps to that described in the AtomPub RFC 5023.  Example 13 shows the payload used to update the category that was inserted in the previous insert example.  Since not all the properties are included in the payload, those not specified will be reset to their default values by the data service.

ATOM:

<entry xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"

    xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"

    xmlns="http://www.w3.org/2005/Atom">

  <content type="application/xml">

   <m:properties>

    <d:CategoryName>Changed Category</d:CategoryName>

   </m:properties>

  </content>

</entry>

JSON:

{

    CategoryName: "Changed Category"

}

Example 15: Payload used to modify an existing Category entity through an HTTP PUT request, Atom and JSON formats

The response from an HTTP PUT request is a 204 (No Content) HTTP response.  In future, we may consider enabling responses similar to that returned from POST requests where the response payload is the latest version of the entity.

Deleting entities

Entities are deleted by executing an HTTP DELETE request against the URL that identifies the entity in the data service. No payload is necessary for a delete operation.

The data service response will not contain a payload. If the entity was deleted successfully then the request will be