2. Consuming ADO.NET Data Services in .NET Applications
When I say .NET applications, I mean applications
that have access to the full .NET stack. This means console
applications, windows applications, and WPF applications, but not
Silverlight.
I'm going to demonstrate this by using a console
application, so start Visual Studio and create a new console application
using the .NET 3.5 framework and call it RestConsoleApp. In this console application, add a service reference to http://sp2010/_vti_bin/ListData.svc, call the generated service reference RESTReference. If you look closely in your project, it would generate a few files (see Figure 6).
Of particular interest here is the service.edmx file.
That describes your EDM. Once that EDM has been described, ADO.NET Data
Services can work on the EDM without much consideration to where the
actual data is coming from. The actual data could be coming from
SharePoint, a database, or an in memory structure; the ADO.NET Data
Services code approach will remain consistent. In the real world,
however, you have to be somewhat careful and consider where the data is
actually coming from. For instance, the SharePoint content database has
been designed for appropriate functioning with minimal oversight; it has
not been designed for extremely high levels of I/O. Thus when
persisting changes using the SaveChanges method, if you use
SaveChangesOptions.Batch on extremely large amounts of data, you may run
the risk of locking your SharePoint content database. Considerations
like these are important in the practical world.
Another thing you would note is that adding the
service reference also generated a strongly typed DataContext for you.
This DataContext reflects the structure of your entire site. This is
similar to LINQ to SharePoint. If the structure of your site changes,
this DataContext is no longer valid. Luckily, they are other approaches
in REST -based APIs that allow you to write code that is slightly more
resistant to schema changes. Those other approaches involve issuing HTTP
requests yourself and parsing the return ATOM or JSON results manually.
An example of that can be seen at http://blah.winsmarts.com/2009-12-How_to_parse_JSON_from_C-.aspx.
Back in our example, go ahead and create an instance of the DataContext:
RESTReference.TestDataContext ctx =
new RESTReference.TestDataContext(
new Uri("http://sp2010/_vti_bin/listdata.svc"))
{
Credentials = CredentialCache.DefaultCredentials
};
The "Test" part of TestDataContext in the code
snippet is reflecting the title of my site. The title of my site was
Test; yours might be different, which also begs this question: is this
approach of adding a reference tying your code too tightly to the site
structure? Yes it certainly is, and you can use other approaches to work
with REST, such as parsing the JSON or ATOM feeds directly, but adding a
reference directly makes your code a lot more readable, perhaps at the
expense of inflexible code.
Because this is a console application I'm passing in
default NTLM credentials. With your DataContext ready to go, you can now
start querying for songs using simple LINQ queries:
var songs = (from item in ctx.Songs
where item.Artist.Title == "George Michael"
select item) as DataServiceQuery<SongsItem>;
foreach (var song in songs)
{
Console.WriteLine(song.Title);
}
When you run that query, also open the Fiddler tool
on the side. You will see the results of the query, showing you the
songs for George Michael (see Figure 7).
In Fiddler, the request being made was as shown here:
GET /_vti_bin/listdata.svc/Songs()?$filter=Artist/Title%20eq%20'George%20Michael' HTTP/1.1
Feel free to examine and fiddle (ha!) a little bit
more with headers that were sent to the server and the results sent back
to the client.
Similar to querying, inserting new data is possible with code shown following:
ctx.AddToArtists(
new ArtistsItem()
{
Title = "Aerosmith"
}
);
ctx.SaveChanges();
The result of inserting new data is captured in Fiddler and is shown in Listing 1.
Example 1. Request Used to Insert New Data in ADO.NET Data Services
POST /_vti_bin/listdata.svc/Artists HTTP/1.1
User-Agent: Microsoft ADO.NET Data Services
Accept: application/ATOM+xml,application/xml
Accept-Charset: UTF-8
DataServiceVersion: 2.0
Content-Type: application/ATOM+xml
Authorization: NTLM
Host: sp2010
Content-Length: 1108
Expect: 100-continue
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<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">
<category scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme"
term="Microsoft.SharePoint.DataService.ArtistsItem" />
<title />
<updated>2009-12-25T09:21:12.4876525Z</updated>
<author>
<name />
</author>
<id />
<content type="application/xml">
<m:properties>
<d:ContentType m:null="true" />
<d:ContentTypeID m:null="true" />
<d:Created m:type="Edm.DateTime" m:null="true" />
<d:CreatedByID m:type="Edm.Int32" m:null="true" />
<d:ID m:type="Edm.Int32">0</d:ID>
<d:Modified m:type="Edm.DateTime" m:null="true" />
<d:ModifiedByID m:type="Edm.Int32" m:null="true" />
<d:Owshiddenversion m:type="Edm.Int32" m:null="true" />
<d:Path m:null="true" />
<d:Title>Aerosmith</d:Title>
<d:Version m:null="true" />
</m:properties>
</content>
</entry>
|
A post request was used to insert new data. If you
were to format a POST request like this through JavaScript or
System.NET, you would get the same results. Sure, the request is
extremely wordy because we are using ATOM. When I describe the
JavaScript equivalent shortly, I will use JSON, and you will then see
how much more terse JSON syntax can be. At this time, verify in the
Artists lists that indeed a new artist was added.
Finally you can delete an artist using this code:
var aeroSmithArtist = from artist in ctx.Artists
where artist.Title == "Aerosmith"
select artist;
ctx.DeleteObject(aeroSmithArtist.First());
ctx.SaveChanges();
As you can see, I'm first querying for the artist I
intend to delete. And then I pass in that entity into the DeleteObject
method. Deleting the artist causes a DELETE HTTP request, as shown in Listing 2.
Example 2. DELETE Http Request to Delete an Artist from SharePoint
DELETE /_vti_bin/listdata.svc/Artists(5) HTTP/1.1
User-Agent: Microsoft ADO.NET Data Services
Accept: application/ATOM+xml,application/xml
Accept-Charset: UTF-8
DataServiceVersion: 2.0
Content-Type: application/ATOM+xml
If-Match: W/"1"
Host: sp2010
Content-Length: 0
|
As you can see from Listing 2,
DELETE passes in the ID of the specific entity you intend to delete.
The one other scenario that I haven't shown here is updating data inside
a SharePoint list, which will cause a PUT query to be executed. I leave
that as an exercise for you to try out.