Separation of presentation and data has long been considered a best practice in the development of Web applications.
Driven by the need for low friction deployment and a richer user experience, the types and architectures of Web applications are evolving dramatically. With the introduction and growth of AJAX-based applications and Rich Interactive Applications (RIA) using technologies such as Microsoft® Silverlight™, separation of presentation and data is no longer just a best practice, it is required.
These architectural changes have been accompanied by a number of new classes of applications. More specifically, two classes of applications have become prevalent in today’s Web landscape: AJAX-based Web applications and RIA applications using technologies such as Microsoft’s Silverlight™. AJAX-based Web applications serve pages containing presentation and behavior, using JavaScript to represent page behavior and then turn back and fetch data separately, using XMLHTTP. Technologies such as these typically remove the option of a server-side rendering process that mixes data and code. Instead, code written to drive the presentation aspects is pre-compiled and deployed to the client via the Web server. After reaching the client Web browser, the code calls back to a Web server to retrieve the data to display within the user interface.
Adding to the classes of applications mentioned, “mashup”-style applications have been introduced, which leverage the presentation/data divide by aggregating data from multiple sources to provide an enhanced experience, using the combined data. This landscape makes it interesting to talk about ADO.NET Data Services (formerly known as Microsoft Project Codename “Astoria”), the services that applications will use, to find and manipulate data on the Web, regardless of the presentation technology used or whether or not the front-end is hosted in the same location or on the same server as the data.
What Are ADO.NET Data Services?
ADO.NET Data Services, provides the ability to expose data as a service, available to clients from across the corporate intranet or across the Internet. These services are then accessible over HTTP, using URIs to identify the pieces of information or “resources” made available through a service. Primary interaction with an ADO.NET Data Service occurs in terms of HTTP verbs such as GET and POST, and the data exchanged in these interactions is represented using simple formats such as XML and JSON.
ADO.NET Data Services, provides the ability to expose data as a service, available to clients from across the corporate intranet or across the Internet. These services are then accessible over HTTP, using URIs to identify the pieces of information or “resources” made available through a service.
In both the AJAX application and RIA application models noted above, data is retrieved via an HTTP request to a middle tier server. Currently, a number of Web service technologies (Windows Communication Foundation, ASMX, etc.) and associated standards (WS-*, SOAP, etc.) exist and may be used to serve data to clients in these scenarios. ADO.NET Data Services and its REST-based access patterns are designed to be complementary to these existing technologies.
For applications that are highly driven by business process and/or typically access data through a rich façade layer, Microsoft has a strong offering in WCF. For applications that are driven more by “pure” data (ex. NetFlix movie queue, stock ticker, etc.) or for data/business logic hybrid applications, ADO.NET Data Services provides a rich offering by enabling the creation of reusable UI elements with a uniform URI addressing scheme. In addition, it also enables the introduction of business logic in a way that is naturally integrated with the rest of the HTTP interface such as ADO.NET Data Services query operators (paging, sorting, etc.) on the server.
Originally introduced as an incubation project from the ADO.NET team under the Microsoft Codename “Astoria” at Mix ’07, ADO.NET Data Services has since moved out from under the “incubation” title and is now a production project. As part of our move from incubation and into development as a production product, we started from scratch using feedback and lessons learned from our initial CTP incubation release. If you have been following ADO.NET Data Services since the beginning, you may notice a few changes to the product in an upcoming technology preview release. Since our initial release we have worked a lot on the architecture of the product, designing it such that we can broaden the capabilities of the product to address the feedback we have received to date without adding undue complexity to the system as a whole.
Using ADO.NET Data Services
ADO.NET Data Services consumes a conceptual model representing the entities that your application wishes to expose, along with the associations between entities, and exposes them as HTTP resources, each identified by a URI. The conceptual model exposed by ADO.NET Data Services is defined using the Entity Data Model (EDM), which is supported by the ADO.NET Entity Framework. By virtue of the ADO.NET Entity Framework, ADO.NET Data Services can expose high-level constructs which are mapped by the framework to the underlying store. For more information on the Entity Framework and EDM, please see Michael Pizzo & Shyam Pather’s articles, also in this issue of CoDe Focus.
Setting up a new ADO.NET Data Service is straightforward and, at the time of this writing, involves creating an EDM model and a data service using wizards in Visual Studio 2008 and then writing a couple lines of code to hook up the data service to the model. The site http://msdn.microsoft.com/data includes links to step-by-step instructions showing how to create a data service using the latest release of ADO.NET Data Services.
The following examples use the read-only Northwind sample database and the experimental ADO.NET Data Services Online Service to detail by example how to interact with an ADO.NET Data Service. As we progress towards a final version of the product, we will likely update the Online Service to reflect our current thinking; however, since the service is experimental the URLs noted below may change or be removed all together over time, so I recommend visiting the ADO.NET Data Services section on http://msdn.microsoft.com/data after reading this article to see if any updates to the URI syntax have been made. For example:
http://astoria.sandbox.live.com/
northwind/northwind.rse/Customers[ALFKI]
returns a single Customer resource. When a URI points a specific resource, you can perform CRUD operations on the resource: An HTTP GET request to the URI enables retrival of the resource, the POST verb is used to add a new instance, the PUT verb to update and, finally, the DELETE verb is used to remove a resource instance.
In addition, it is possible to traverse associations between resources using a URI such as:
http://astoria.sandbox.live.com/northwind
/northwind.rse/Customers[city eq
'London']/Orders?$orderby=OrderDate
This URI represents all the Orders for the Customers living in London, where the results are returned sorted by the OrderDate.
The documents linked to from the developer center noted above details all the URI construction rules, available query operators as well as the data formats supported in HTTP requests and responses to/from an ADO.NET Data Service. At the time of this writing, the latest CTP release supports simple data formats such as XML and JSON. For an in-depth overview of the formats used by ADO.NET Data Services, please see http://msdn.microsoft.com/data.
Rich Client Access
Since all ADO.NET Data Service resources are exposed by simple HTTP entry points, any application with the ability to make an HTTP request can access a data service. In addition to direct HTTP access using an HTTP API, client libraries are available for the .NET Framework and Silverlight 1.1 applications. As well as abstracting the application from the base semantics of HTTP, the libraries surface results as .NET objects and provide rich services to the application such as graph management, change tracking, and update processing.
For AJAX applications, most AJAX libraries include some type of easy-to-use wrapper object over the XMLHTTP object. To facilitate this usage model, ADO.NET Data Services supports requests and responses in JSON format. This enables a payload returned from a data service to be used as the parameter to the JavaScript Eval( ) function, which enables the AJAX application to directly materialize JavaScript constructs from the response from a data service.
Going Beyond “Pure Data”
So far I have described how ADO.NET Data Services map a URI to each entity within an EDM-based conceptual model, which a developer defines and provides to a data service to expose as HTTP resources. This approach works well for classes of data (ex. blog articles) that can be served from the storage medium all the way to the application where it is likely to be directly presented to the end user. While such data exists, it is clear that not all data fits this mold. Some types of data will, for a variety of reasons (validation, etc), need to be accompanied by business logic that governs how the data is served.
ADO.NET Data Services enables a developer to go beyond the pure data model where required by defining service operations and/or interceptors. Service operations allow the developer of a data service to define a method on the server, which just like all other ADO.NET Data Service resources, is identified by a URI. For example, the URI /MyFavoriteBooks?category=sports&$OrderBy=Title represents a call to the service operation named MyFavoriteBooks that takes a single category parameter. One of the interesting features of service operations is that if the operation on the service returns a query representing the resource to return as opposed to the resource itself, then as shown in the example above, the output of the service operation can be acted on using standard ADO.NET Data Service operations. This is shown in the query string of the example above where the OrderBy operator is applied to the results of the operation.
Another mechanism known as interceptors is provided to data services, which enables a developer to plug in custom validation logic into the request/response processing pipeline of a data service. Interceptors allow a developer to register a method to be called when a particular CRUD action occurs on a given type of resource being exposed by ADO.NET Data Services. Such a method then may alter the data or even terminate the operation.
Looking Forward
Applications are moving to a model which divides behavior and presentation from data access. This trend has been driven by the ability of such architectures to deliver a rich, interactive client experience. ADO.NET Data Services provide a simple, uniform way for applications to access their data. Uniformity in this regard simplifies data access and enables opportunities for generic UI controls and libraries to be constructed based on a well-known pattern.
ADO.NET Data Services is currently in active development. Unfortunately, this article is unable to cover all aspects of this new technology. We’ll strive to be very transparent with our blog at http://blogs.microsoft.com/astoriateam. There you’ll learn more about how ADO.NET Data Services is progressing and find out more on our current thinking in various aspects of the product design, plus you can provide us with your feedback.