88 articles and 350 comments as of Wednesday, April 4th, 2012

Thursday, April 29, 2010

Client Side AJAX Applications in SharePoint 2010 – Part 2: WCF Data Services

Guest Author: Lee Richardson
http://rapidapplicationdevelopment.blogspot.com/

As I mentioned in Part 1, WCF Data Services is one of the most compelling new features of SharePoint 2010 from a developer’s perspective.  In this post I’ll describe what it is and how it works.  I’ll leave implementing something with it using ASP.Net AJAX Templating to subsequent articles in the series.

Confused Yet?

The chances are good you’re familiar with the technology, but not with the name WCF Data Services.  The reason for the confusion is that there are currently four terms that all refer to essentially the same thing.  The technology debuted with the codename Astoria in 2007 – a term still in use today.  It launched as ADO.Net Data Services in December of 2007.  The name was changed to WCF Data Services in 2009.  And in March of this year Microsoft released a group of specifications collectively known as the Open Data Protocol, or oData, of which WCF Data Services is an implementation (for more detail on oData check out Scott Hanselman’s excellent podcast on the topic).

Unfortunately SharePoint 2010 doesn’t come with WCF Data Services out of the box.  But fortunately it’s free and easy to add: just download and install the Data Services Update for .NET Framework 3.5 SP1 (or ADO Data Services v1.5 if you’re still running SharePoint 2010 Beta).   You can confirm it’s installed on your server by navigating to http://[server]/[optional site]/_vti_bin/ListData.svc.  If it’s installed correctly you’ll see an ATOM feed of all of the lists you have permission to view.  The result will look like this:

<?xml version="1.0" encoding="iso-8859-1" standalone="yes"?>
<service xml:base="http://localhost/mySite/_vti_bin/ListData.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="Iterations">
      <atom:title>Iterations</atom:title>
    </collection>
    <collection href="UserStories">
      <atom:title>UserStories</atom:title>
    </collection>
  </workspace>
</service>

Navigating a Sea of XML

By default WCF Data Services displays its data as ATOM feeds which include links to URL’s that can provide more data.  For instance the href=”UserStories” attribute shown above tells us that we can append “/UserStories” to the end of our existing URL to view list items in the User Stories list.  The result looks like this:

<?xml version="1.0" encoding="iso-8859-1" standalone="yes"?>
<feed xml:base="http://localhost/mySite/_vti_bin/ListData.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">
  <title type="text">UserStories</title>
  <id>http://localhost/mySite/_vti_bin/ListData.svc/UserStories</id>
  <updated>2010-03-20T02:20:26Z</updated>
  <link rel="self" title="UserStories" href="UserStories" />
  <entry m:etag="W/&quot;3&quot;">
    <id>http://localhost/mySite/_vti_bin/ListData.svc/UserStories(2)</id>
    <title type="text">Do Something</title>
    <updated>2010-03-19T15:13:28-05:00</updated>
    <author>
      <name />
    </author>
    <link rel="edit" title="UserStoriesItem" href="UserStories(2)" />
    <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Predecessors"
        type="application/atom+xml;type=feed"
        title="Predecessors"
        href="UserStories(2)/Predecessors" />
    <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Priority"
        type="application/atom+xml;type=entry"
        title="Priority"
        href="UserStories(2)/Priority" />
    <link
        rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Status"
        type="application/atom+xml;type=entry"
        title="Status"
        href="UserStories(2)/Status" />
    <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Iteration"
        type="application/atom+xml;type=entry"
        title="Iteration"
        href="UserStories(2)/Iteration" />
    <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Attachments"
        type="application/atom+xml;type=feed"
        title="Attachments"
        href="UserStories(2)/Attachments" />
    <category
        term="Microsoft.SharePoint.DataService.UserStoriesItem"
        scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
    <content type="application/xml">
      <m:properties>
        <d:ContentTypeID>0x01080070E2807D369BD94FBD6C057D3110E6D3</d:ContentTypeID>
        <d:Title>Do Something</d:Title>
        <d:PriorityValue>(2) Normal</d:PriorityValue>
        <d:StatusValue>Not Started</d:StatusValue>
        <d:Complete m:type="Edm.Double" m:null="true" />
        <d:AssignedToID m:type="Edm.Int32" m:null="true" />
        <d:TaskGroupID m:type="Edm.Int32" m:null="true" />
        <d:Description>&lt;div&gt;&lt;/div&gt;</d:Description>
        <d:StartDate m:type="Edm.DateTime">2010-02-20T00:00:00</d:StartDate>
        <d:DueDate m:type="Edm.DateTime" m:null="true" />
        <d:Points m:type="Edm.Double">3</d:Points>
        <d:IterationID m:type="Edm.Int32">3</d:IterationID>
        <d:ID m:type="Edm.Int32">2</d:ID>
        <d:ContentType>Task</d:ContentType>
        <d:Modified m:type="Edm.DateTime">2010-03-19T15:13:28</d:Modified>
        <d:Created m:type="Edm.DateTime">2010-02-20T15:32:26</d:Created>
        <d:CreatedByID m:type="Edm.Int32">1</d:CreatedByID>
        <d:ModifiedByID m:type="Edm.Int32">1</d:ModifiedByID>
        <d:Owshiddenversion m:type="Edm.Int32">3</d:Owshiddenversion>
        <d:Version>3.0</d:Version>
        <d:Path>/mySite/Lists/User Stories</d:Path>
      </m:properties>
    </content>
  </entry>
</feed>

That’s showing us that there is one list item in the list with a title of “Do Something” and among other things a Priority of “(2) Normal”.

If we had more list items we could retrieve the data in different ways by appending different query string parameters.  The most common operations are filtering, sorting, and paginating.  For example http://localhost/site/_vti_bin/ListData.svc/UserStories?$filter=(PriorityValue eq ‘(2) Normal’)&$orderby=Title will return list items whose priority is normal sorted by title. 

If you’re interested in details on the URL syntax you can read more about Query Expressions on MSDN.  However, more often than not you won’t be using URL’s directly.  For instance you could use the beta version of LINQPad which now supports querying WCF Data Services.


Or better yet, as we’ll see in future articles, ASP.Net AJAX 4 contains JavaScript objects that know how to query WCF Data Services natively.

WCF Data Services: More than Just XML

If thus far you’ve been turned off by all this XML, there’s some good news.  WCF Data Services exposes its data in other formats too.  For instance if you modify the HTTP header of your request you can retrieve all of the same data you’ve seen so far as JSON.  How do you modify the HTTP headers?  Microsoft has a tool called Fiddler that does just that.

If you’ve installed Fiddler you can open it from the add-in in your browser and navigate to the WCF Data Services URL for a list.  You can drag the last request to the Request Builder (ensure “Automatically Authenticate” is checked in options), and replace “Accept: */*” with “Accept application/json”. And if you click Execute you should see something like this:

{
"d" : {
"results": [
{
"__metadata": {
"uri": "http://localhost/demoprep/_vti_bin/ListData.svc/UserStories(2)",
"etag": "W/\"3\"",
"type": "Microsoft.SharePoint.DataService.UserStoriesItem"
}, "ContentTypeID": "0x01080070E2807D369BD94FBD6C057D3110E6D3",
"Title": "Blah",
"Predecessors": {
"__deferred": {
"uri": "http://localhost/demoprep/_vti_bin/ListData.svc/UserStories(2)/Predecessors"
}
}, "Priority": {
"__deferred": {
"uri": "http://localhost/demoprep/_vti_bin/ListData.svc/UserStories(2)/Priority"
}
}, "PriorityValue": "(2) Normal", "Status": {
"__deferred": {
"uri": "http://localhost/demoprep/_vti_bin/ListData.svc/UserStories(2)/Status"
}
}, "StatusValue": "Not Started",
"Complete": null,
"AssignedToID": null,
"TaskGroupID": null,
"Description": "<div></div>",
"StartDate": "\/Date(1266624000000)\/",
"DueDate": null,
"Points": 3,
"Iteration": {
"__deferred": {
"uri": "http://localhost/demoprep/_vti_bin/ListData.svc/UserStories(2)/Iteration"
}
}, "IterationID": 3,
"ID": 2,
"ContentType": "Task",
"Modified": "\/Date(1269011608000)\/",
"Created": "\/Date(1266679946000)\/",
"CreatedByID": 1,
"ModifiedByID": 1,
"Owshiddenversion": 3,
"Version": "3.0",
"Attachments": {
"__deferred": {
"uri": "http://localhost/demoprep/_vti_bin/ListData.svc/UserStories(2)/Attachments"
}
}, "Path": "/demoprep/Lists/User Stories"
}
]
}
}


That’s SharePoint data as lightweight JavaScript Object Notation. Notice the etag for caching.  Cool.

But ListData.svc isn’t just for reading data. To experiment with it try deleting a list item. To do this in fiddler set the HTTP verb to “DELETE”, set the URL to a particular list item’s URL (e.g. http://localhost/site/_vti_bin/ListData.svc/UserStories(2) where 2 is the ID for a list item), leave Request Headers empty, and hit Execute. Refresh the list of items and it’s gone. Permanently. The item isn’t even in the recycle bin.

More than Just a Data Access Layer

So at this point you are undoubtedly concerned about security.  Who is keeping users out of sensitive data?  Who is keeping them from accidentally or even maliciously deleting data?  The good news is that SharePoint is without any additional effort on your part.

SharePoint handles the security for WCF Data Services the same way it does when users navigate through the web.  If a user doesn’t have access to a list then they won’t see links to it.  If they try to access the list anyway, they’ll get a 404.  If they modify the row level permissions for a list item to deny read permissions for a particular user, then WCF Data Services will omit that row when it returns its data.  And if they try to modify or delete a list item they don’t have permissions to, then SharePoint returns a 401 Unauthorized.

But WCF Data Services does even more than just security.  It also handles validation.  If a user tries to insert null into a required field, they get back an HTTP error code.  If they violate one of the SharePoint 2010’s new list level validation rules, they get back an HTTP error code.  If they try to violate SharePoint 2010’s wonderful new uniqueness constraint, they get an HTTP error code.

That’s powerful.  And that’s also a lot of code you don’t have to write – or maintain.

Summary

So far we’ve seen a behind-the-scenes view of a technology that enables some powerful client side AJAX applications in SharePoint 2010.  We haven’t seen anything beautiful yet (from an end user’s perspective) but we’ve set the scenes for writing responsive, pretty, web based applications that end users will love.  And that’s where ASP.Net AJAX Templating comes in – which, conveniently enough, happens to be the subject of the next post in this series.

Guest Author: Lee Richardson
http://rapidapplicationdevelopment.blogspot.com/

Lee Richardson is a Senior Software Engineer at Near Infinity Corporation, an enterprise software development and consulting services company based in Reston, Virginia. He is a Microsoft Certified Solution Developer (MCSD), a Project Management Professional (PMP), a Certified SCRUM master and has over ten years of experience consulting for the public and private sector. You can follow Lee on Twitter at @lprichar

Bookmark and Share
 

Please Join the Discussion

2 Responses to “Client Side AJAX Applications in SharePoint 2010 – Part 2: WCF Data Services”
  1. David Smith says:

    Lee,
    Do you have an info/posts that go more into detail on how SharePoint 2010 does authentication when a service client tries to call ListData.svc? For instace, under the following senarios:
    - client calling from another domain

  2. alvin says:

    hello,
    I am trying to query lists in SharePoint with what I was thinking was a simple visual web part. It was suppose to list the all the lists in the site and give some properties on each (VS2010 lab from Channel9). I am working on SP2010 running on Server2008(VM) with VS2010 and Linqpad(.Net3.5).

    The visual web part, which looked nice on any site did not retrieve any list data. That failure led me to get down to a more basic level of how can I query SharePoint, Hence your posts.

    I ran the browser check you listed above and it works for both Central Admin and the Top Level site. When I add a data connection for Linqpad for Central Admin the connection is successful, but not so for the Top Level site. The same is true when I add a “SharePoint Connection” in VS2010.

    any Ideas? Could it be a permissions problem. I will continue reading through your post (thanks for putting this together by the way), but it would be really helpful if I could get them to work on this box.

    cheers,

    alvin

Subscribe without commenting

Speak and you will be heard.

We check comments hourly.
If you want a pic to show with your comment, go get a gravatar!