Accessing SharePoint 2010 Data with REST/OData on Windows Phone 7

Consuming SharePoint 2010 data in Windows Phone 7 applications using the CTP version of the developer tools is quite a challenge. The issue is that the SharePoint 2010 data is not anonymously available; users need to authenticate to be able to access the data. When I first tried to access SharePoint 2010 data from my first Hello-World-type Windows Phone 7 application I thought “Hey, this should be easy!” because Windows Phone 7 development based on Silverlight and SharePoint 2010 has a Client Object Model for Silverlight. Unfortunately you can’t use the Client Object Model of SharePoint 2010 on the Windows Phone platform; there’s a reference to an assembly that’s not available (System.Windows.Browser).

My second thought was “OK, no problem!” because SharePoint 2010 also exposes a REST/OData API to access SharePoint data. Using the REST API in SharePoint 2010 is as easy as making a web request for a URL (in which you specify the data you’d like to retrieve), e.g. http://yoursiteurl/_vti_bin/listdata.svc/Announcements. This is very easy to accomplish in a Silverlight application that’s running in the context of a page in a SharePoint site, because the credentials of the currently logged on user are automatically picked up and passed to the WCF service. But a Windows Phone application is of course running outside of the SharePoint site’s page, so the application should build credentials that have to be passed to SharePoint’s WCF service. This turns out to be a small challenge in Silverlight 3, the WebClient doesn’t support authentication; there is a Credentials property but when you set it and make the request you get a NotImplementedException exception.

Probably this issued will be solved in the very near future, since Silverlight 4 does support authentication, and there’s already a WCF Data Services download that uses this new platform feature of Silverlight 4. So when Windows Phone platform switches to Silverlight 4, you can just use the WebClient to get the data. Even more, if the OData Client Library for Windows Phone 7 gets updated after that, things should get even easier! By the way: the things I’m writing in this paragraph are just assumptions that I make which make a lot of sense IMHO, I don’t have any info all of this will happen, but I really hope so.

So are SharePoint developers out of the Windows Phone development game until they get this fixed? Well luckily not, when the HttpWebRequest class is being used instead, you can pass credentials! Using the HttpWebRequest class is slightly more complex than using the WebClient class, but the end result is that you have access to your precious SharePoint 2010 data. The following code snippet is getting all the announcements of an Annoucements list in a SharePoint site:

HttpWebRequest webReq =
    (HttpWebRequest)HttpWebRequest.Create("
http://yoursite/_vti_bin/listdata.svc/Announcements");
webReq.Credentials = new NetworkCredential("username", "password");

webReq.BeginGetResponse(
    (result) => {
        HttpWebRequest asyncReq = (HttpWebRequest)result.AsyncState;

        XDocument xdoc = XDocument.Load(
            ((HttpWebResponse)asyncReq.EndGetResponse(result)).GetResponseStream());

        XNamespace ns = "http://www.w3.org/2005/Atom";
        var items = from item in xdoc.Root.Elements(ns + "entry")
                    select new { Title = item.Element(ns + "title").Value };

        this.Dispatcher.BeginInvoke(() =>
        {
            foreach (var item in items)
                MessageBox.Show(item.Title);
        });
    }, webReq);

When you try this in a Windows Phone 7 application, make sure you add a reference to the System.Xml.Linq assembly, because the code uses Linq to XML to parse the resulting Atom feed, so the Title of every announcement is being displayed in a MessageBox. Check out my previous post if you’d like to see a more polished sample Windows Phone 7 application that displays SharePoint 2010 data.
When you plan to use this technique, it’s of course a good idea to encapsulate the code doing the request, so it becomes really easy to get the data that you need. In the following code snippet you can find the GetAtomFeed method that gets the contents of any Atom feed, even if you need to authenticate to get access to the feed.

delegate void GetAtomFeedCallback(Stream responseStream);

public MainPage()
{
    InitializeComponent();

    SupportedOrientations = SupportedPageOrientation.Portrait |
        SupportedPageOrientation.Landscape;

    string url = "http://yoursite/_vti_bin/listdata.svc/Announcements";
    string username = "username";
    string password = "password";
    string domain = "";

    GetAtomFeed(url, username, password, domain, (s) =>
    {
        XNamespace ns = "
http://www.w3.org/2005/Atom";
        XDocument xdoc = XDocument.Load(s);

        var items = from item in xdoc.Root.Elements(ns + "entry")
                    select new { Title = item.Element(ns + "title").Value };

        this.Dispatcher.BeginInvoke(() =>
        {
            foreach (var item in items)
            {
                MessageBox.Show(item.Title);
            }
        });
    });
}

private static void GetAtomFeed(string url, string username,
    string password, string domain, GetAtomFeedCallback cb)
{
    HttpWebRequest webReq = (HttpWebRequest)HttpWebRequest.Create(url);
    webReq.Credentials = new NetworkCredential(username, password, domain);

    webReq.BeginGetResponse(
        (result) =>
        {
            HttpWebRequest asyncReq = (HttpWebRequest)result.AsyncState;
            HttpWebResponse resp = (HttpWebResponse)asyncReq.EndGetResponse(result);
            cb(resp.GetResponseStream());
        }, webReq);
}

No Comments