SharePoint 2010 introduced the client-side object model (CSOM) to allow developers to write applications which interact with SharePoint from client-side code. In SharePoint 2013, Microsoft steps things up a notch by allowing developers to use Representational State Transfer (REST) in conjunction with the Open Data (OData) protocol to perform Create/Read/Update/Delete (CRUD) operations against SharePoint sites and lists for nearly every API in the CSOM. Through the magic of CloudShare web access, we can leverage the CSOM along with REST and OData to interact with our SharePoint 2013 environments from literally anywhere, using any type of client! All code samples in this blog post will be run from my local workstation over 1,000 miles away from my SharePoint 2013 server running in the CloudShare datacenter!
For this post, I have set up a CloudShare environment that includes the SharePoint Server 2013 RTM machine. I have also set up the Vanity URL http://dannyjessee.cld.sr for external web access to the machine. (If you haven’t already, I highly recommend that you set up a Vanity URL for your environment, too!) I then added my Vanity URL as an Alternate Access Mapping (AAM) for my SharePoint 2013 web application:
Using the CSOM to Add a SharePoint List with Items
The CSOM is still the mechanism of choice for interacting with SharePoint 2013 from remote .NET clients. If you are going to develop applications that interact with SharePoint 2013 from a machine that is not running SharePoint 2013, you will need to download and install the SharePoint Server 2013 Client Components SDK. This package contains the necessary DLLs to reference the CSOM (Microsoft.SharePoint.Client.dll and Microsoft.SharePoint.Client.Runtime.dll) and run your application. Juan Carlos provides further information about what’s new in the CSOM for SharePoint 2013 in his blog post here.
In Visual Studio 2012, I created a new console application and added references to the two DLLs necessary to leverage the CSOM that I mentioned above. I also added a using directive for Microsoft.SharePoint.Client. I wrote the following code to add a new list to my site using the Contacts list template:
// Use your CloudShare web access/Vanity URL herestring siteUrl = "http://dannyjessee.cld.sr";ClientContext context = new ClientContext(siteUrl);context.AuthenticationMode = ClientAuthenticationMode.Default;// Obtain these values from your environment's home pagecontext.Credentials = new NetworkCredential("username", "password", "domain");Web web = context.Web;context.Load(web);context.ExecuteQuery();ListCreationInformation creationInfo = new ListCreationInformation();creationInfo.Title = "MySpecialContactsList";creationInfo.TemplateType = (int)ListTemplateType.Contacts;List list = web.Lists.Add(creationInfo);list.Description = "My Special Contacts List Description";list.Update();context.ExecuteQuery();ListItemCreationInformation itemCreateInfo = new ListItemCreationInformation();ListItem newItem = list.AddItem(itemCreateInfo);newItem["FirstName"] = "Danny";newItem["Title"] = "Jessee"; // Mapped to "Last Name" fieldnewItem.Update();itemCreateInfo = new ListItemCreationInformation();newItem = list.AddItem(itemCreateInfo);newItem["FirstName"] = "John";newItem["Title"] = "Doe"; // Mapped to "Last Name" fieldnewItem.Update();context.ExecuteQuery();
Executing this code (with the appropriate credentials specified) will add the list MySpecialContactsList to my site with two items added to the list based on the values I provided:
A SharePoint REST and OData Primer
SharePoint 2013’s REST service provides access to the capabilities available through the CSOM. It enables developers to perform CRUD operations against data stored in SharePoint using the OData protocol. Nearly all CSOM APIs have a corresponding REST endpoint. JavaScript and non-.NET clients benefit the most from leveraging SharePoint 2013’s REST/OData endpoints.
In SharePoint 2013, the alias /_api has been added as shorthand for /_vti_bin/client.svc. With that in mind, a RESTful call to get information about the root SPWeb of my SharePoint 2013 web application can be made to the URL http://dannyjessee.cld.sr/_api/web. Entering this URL in the browser (and providing credentials) produces the following output:
To retrieve a specific piece of information (in this case, the Title property of the SPWeb), we use the OData $select operator and make a request to the URL http://dannyjessee.cld.sr/_api/web/?$select=Title, which reveals the “Incredibly Awesome” name I have given my site:
This is all very interesting, and while it is helpful to be able to use a web browser to test making GET requests to SharePoint 2013’s REST/OData endpoints. However, the true power in this approach lies in the ability to perform CRUD operations from external clients without running any custom code on the SharePoint server. In the next section, I will demonstrate how to perform these operations in a .NET client.
Creating, Updating, and Deleting list items using SharePoint’s REST Service
The code below makes HTTP requests to SharePoint’s REST service endpoints to add a new list item, update an existing list item, and delete a list item:
// Use your CloudShare web access/Vanity URL herestring siteUrl = "http://dannyjessee.cld.sr";// 1. Add a new item to the listUri uri = new Uri(siteUrl + "_api/web/lists/GetByTitle('MySpecialContactsList')/Items");HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);request.Method = "POST";request.Credentials = new NetworkCredential("username", "password", "domain");request.Accept = "application/json;odata=verbose";request.ContentType = "application/json;odata=verbose";request.Headers["X-RequestDigest"] = GetFormDigest();string body = "{'__metadata':{'type':'SP.Data.MySpecialContactsListListItem'},'Title':'Jones','FirstName':'Adam'}";request.ContentLength = body.Length;StreamWriter writer = new StreamWriter(request.GetRequestStream());writer.Write(body);writer.Flush();HttpWebResponse response = (HttpWebResponse)request.GetResponse();// 2. Update an existing item in the listuri = new Uri(siteUrl + "_api/web/lists/GetByTitle('MySpecialContactsList')/Items(1)");request = (HttpWebRequest)WebRequest.Create(uri);request.Method = "POST";request.Credentials = new NetworkCredential("username", "password", "domain");request.Accept = "application/json;odata=verbose";request.ContentType = "application/json;odata=verbose";request.Headers["X-HTTP-Method"] = "MERGE";request.Headers["If-Match"] = "*";request.Headers["X-RequestDigest"] = GetFormDigest();body = "{'__metadata':{'type':'SP.Data.MySpecialContactsListListItem'},'Title':'Jessee, Jr.'}";request.ContentLength = body.Length;writer = new StreamWriter(request.GetRequestStream());writer.Write(body);writer.Flush();response = (HttpWebResponse)request.GetResponse();// 3. Delete an item from the listuri = new Uri(siteUrl + "_api/web/lists/GetByTitle('MySpecialContactsList')/Items(2)");request = (HttpWebRequest)WebRequest.Create(uri);request.Method = "POST";request.Credentials = new NetworkCredential("username", "password", "domain");request.Accept = "application/json;odata=verbose";request.ContentType = "application/json;odata=verbose";request.Headers["X-HTTP-Method"] = "DELETE";request.Headers["If-Match"] = "*";request.Headers["X-RequestDigest"] = GetFormDigest();request.ContentLength = 0;response = (HttpWebResponse)request.GetResponse();
Any code that updates SharePoint via an HTTP POST requires a value to be specified for the X-RequestDigest HTTP header. For code running outside of SharePoint, this the value must be retrieved by making a separate HTTP POST request to the _api/contextinfo endpoint. To accomplish this, I made use of the following method (courtesy of Ted Pattison’s post here):
string GetFormDigest(){// To get the form digest for external calls, need to make a POST request to// http://siteUrl/_api/contextinfoUri uri = new Uri(siteUrl + "_api/contextinfo");HttpWebRequest requestPost = (HttpWebRequest)WebRequest.Create(uri);requestPost.Credentials = new NetworkCredential("username", "password", "domain");requestPost.Method = "POST";requestPost.ContentLength = 0;HttpWebResponse responsePost = (HttpWebResponse)requestPost.GetResponse();XDocument doc = XDocument.Load(responsePost.GetResponseStream());XNamespace ns_dataservices = "http://schemas.microsoft.com/ado/2007/08/dataservices";return doc.Descendants(ns_dataservices + "FormDigestValue").First().Value;}
Executing this code (again, with the appropriate credentials specified) will add an entry for Adam Jones, update my last name to “Jessee, Jr.”, and delete the entry for John Doe:
Conclusion
Microsoft has made significant investments in enhancing and extending the CSOM, along with SharePoint’s REST/OData endpoints, to provide developers with the richness and flexibility that was previously only available through the server-side object model. These enhancements enable developers to take advantage of the new app model for SharePoint 2013 as well as develop feature-rich client and web-based applications whose code runs exclusively in the cloud (or on any server external to SharePoint). This improves the overall stability of the SharePoint platform and paves the way for less troublesome upgrades down the road.