Working with the REST API in C#
Using the REST API from a C# application is certainly possible, but
it is easily the least attractive of all the programming options. You
will find that retrieving form digests, parsing out properties, and
creating payloads can be tedious and messy. This section details the
steps necessary to work with the REST API in C#.
Example 9 shows the same code rewritten in a provider-hosted app. The code runs within the Page_Load event and welcomes the user to the app.
Example 9. Welcoming the current user
protected void Page_Load(object sender, EventArgs e)
{
//Construct URI
string appWebUrl = Page.Request["SPAppWebUrl"];
Uri uri = new Uri(appWebUrl + "/_api/web/currentuser");
//Perform GET operation
HttpWebRequest restRequest = (HttpWebRequest)WebRequest.Create(uri);
restRequest.Credentials = CredentialCache.DefaultCredentials;
restRequest.Method = "GET";
HttpWebResponse restResponse = (HttpWebResponse)restRequest.GetResponse();
//Parse out Title
XDocument atomDoc = XDocument.Load(restResponse.GetResponseStream());
XNamespace ns = "http://schemas.microsoft.com/ado/2007/08/dataservices";
message.Text = "Hello " + atomDoc.Descendants(ns + "Title").First().Value;
}
The code in Example 9 begins by constructing a URI to request the current user object from the REST API. The URI is invoked by using the HttpWebRequest object, which uses the HTTP GET verb and returns the data in AtomPub format. Finally, the Title
property is extracted from the returned XML document by using
LINQ-to-XML. You can see that the mechanics of using the REST API are
the same in C# as they are in JavaScript, but the implementation is not as clean.
Performing CRUD operations with
C# against the REST API can be a bit challenging. This is because you
must go through an extra step to retrieve a form digest and because you
must create the proper XML payloads by hand. Fortunately, you can
encapsulate the basic CRUD functionality in a static class to make it easier. Example 10 shows a basic class
structure for encapsulating CRUD operations against the REST API. In
keeping with previous examples, the class targets a contacts list in
the app.
Example 10. A class for REST operations
namespace Wingtip
{
public static class Contacts
{
public static string AppWebUrl;
public static void CreateItem(string LastName,
string FirstName,
string WorkPhone){}
public static List<TableRow> ReadAll(){}
public static void UpdateItem(string ID,
string LastName,
string FirstName,
string WorkPhone){}
public static void RemoveItem(string ID){}
private static string GetFormDigest(){}
}
}
The structure of the static class in Example 10
is similar to libraries that were shown previously in JavaScript, which
contained methods for creating, reading, updating, and deleting. When using C# against the REST API, however, there are two new elements to consider. First, a static variable AppWebUrl is added to make the root URL of the app available to all the methods. Second, a private method named GetFormDigest is added to retrieve the form digest when necessary.
When you use C#
against the REST API, it will always be from a remote web. Therefore,
you don’t have the luxury of the form digest control being present on
the app page. Because of this, you must make a separate RESTful call
back to SharePoint solely to retrieve a form digest that can be used in
the CRUD operations. Example 11 shows the implementation of the GetFormDigest method, which returns the form digest as a string.
Example 11. Retrieving the form digest
private static string GetFormDigest()
{
Uri uri = new Uri(AppWebUrl + "/_api/contextinfo");
HttpWebRequest restRequest = (HttpWebRequest)WebRequest.Create(uri);
restRequest.Credentials = CredentialCache.DefaultCredentials;
restRequest.Method = "POST";
restRequest.ContentLength = 0;
HttpWebResponse restResponse = (HttpWebResponse)restRequest.GetResponse();
XDocument atomDoc = XDocument.Load(restResponse.GetResponseStream());
XNamespace d = "http://schemas.microsoft.com/ado/2007/08/dataservices";
return atomDoc.Descendants(d + "FormDigestValue").First().Value;
}
Creating new items in
C# requires the same basic approach as JavaScript. A URI is constructed
that refers to the collection to which the new items are to be added
and the POST verb is used
to send an XML chunk containing the data for the new item. In C#, you
must create the XML by hand and substitute in the new values. Example 12 shows the code to create a new item in the contacts list.
Example 12. Creating new items in a contacts list
public static void CreateItem(string LastName, string FirstName, string
WorkPhone)
{
Uri uri = new Uri(AppWebUrl +
"/_api/web/lists/getByTitle('Contacts')/items");
string itemXML = String.Format(@"
<entry xmlns='http://www.w3.org/2005/Atom'
xmlns:d='http://schemas.microsoft.com/ado/2007/08/dataservices'
xmlns:m='http://schemas.microsoft.com/ado/2007/08/dataservices/
metadata'>
<category term='SP.Data.ContactsListItem'
scheme='http://schemas.microsoft.com/ado/2007/08/dataservices/
scheme' />
<content type='application/xml'>
<m:properties>
<d:FirstName>{0}</d:FirstName>
<d:Title>{1}</d:Title>
<d:WorkPhone>{2}</d:WorkPhone>
</m:properties>
</content>
</entry>", FirstName, LastName, WorkPhone);
HttpWebRequest restRequest = (HttpWebRequest)WebRequest.Create(uri);
restRequest.Credentials = CredentialCache.DefaultCredentials;
restRequest.Method = "POST";
restRequest.Headers["X-RequestDigest"] = GetFormDigest();
restRequest.Accept = "application/atom+xml";
restRequest.ContentType = "application/atom+xml";
restRequest.ContentLength = itemXML.Length;
StreamWriter sw = new StreamWriter(restRequest.GetRequestStream());
sw.Write(itemXML);
sw.Flush();
HttpWebResponse restResponse = (HttpWebResponse)restRequest.GetResponse();
}
Reading items is fairly straightforward. You can simply create the URI referencing the items to return and make the call. Example 13 illustrates the implementation of the ReadAll method for the sample. In this case, the method returns a collection of type TableRow, which is subsequently added to an ASP.NET Table control to display the items.
Example 13. Reading list items
public static List<TableRow> ReadAll()
{
Uri uri = new Uri(AppWebUrl +
"/_api/web/lists/getByTitle('Contacts')/items/" +
"?$select=Id,FirstName,Title,WorkPhone" +
"&$orderby=Title,FirstName");
HttpWebRequest restRequest = (HttpWebRequest)WebRequest.Create(uri);
restRequest.Credentials = CredentialCache.DefaultCredentials;
restRequest.Method = "GET";
HttpWebResponse restResponse = (HttpWebResponse)restRequest.GetResponse();
XDocument atomDoc = XDocument.Load(restResponse.GetResponseStream());
XNamespace a = "http://www.w3.org/2005/Atom";
XNamespace d = "http://schemas.microsoft.com/ado/2007/08/dataservices";
List<TableRow> rows = new List<TableRow>();
foreach (var entry in atomDoc.Descendants(a + "entry"))
{
TableRow r = new TableRow();
TableCell c1 = new TableCell();
c1.Text = entry.Descendants(d + "Id").First().Value;
TableCell c2 = new TableCell();
c2.Text = entry.Descendants(d + "FirstName").First().Value;
TableCell c3 = new TableCell();
c3.Text = entry.Descendants(d + "Title").First().Value;
TableCell c4 = new TableCell();
c4.Text = entry.Descendants(d + "WorkPhone").First().Value;
r.Cells.Add(c1);
r.Cells.Add(c2);
r.Cells.Add(c3);
r.Cells.Add(c4);
rows.Add(r);
}
return rows;
}
Updating items is also done by using
the same basic approach presented with JavaScript. A URI is constructed
that refers to the item to be updated. The XML chunk containing the new
property values must be created and a form digest added to the headers.
Additionally, the PATCH
method is used to allow only the desired properties to be updated.
Finally, the corresponding ETag value must be supplied or an asterisk
used to force an update. Example 14 shows the complete implementation of the method to update items in the contacts list.
Example 14. Updating items in a contacts list
public static void UpdateItem(string ID, string LastName, string FirstName,
string WorkPhone)
{
Uri uri = new Uri(AppWebUrl +
"/_api/web/lists/getByTitle('Contacts')/items(" + ID + ")");
string itemXML = String.Format(@"
<entry xmlns='http://www.w3.org/2005/Atom'
xmlns:d='http://schemas.microsoft.com/ado/2007/08/dataservices'
xmlns:m='http://schemas.microsoft.com/ado/2007/08/dataservices/
metadata'>
<category term='SP.Data.ContactsListItem'
scheme='http://schemas.microsoft.com/ado/2007/08/dataservices/
scheme' />
<content type='application/xml'>
<m:properties>
<d:FirstName>{0}</d:FirstName>
<d:Title>{1}</d:Title>
<d:WorkPhone>{2}</d:WorkPhone>
</m:properties>
</content>
</entry>", FirstName, LastName, WorkPhone);
HttpWebRequest restRequest = (HttpWebRequest)WebRequest.Create(uri);
restRequest.Credentials = CredentialCache.DefaultCredentials;
restRequest.Method = "POST";
restRequest.Headers["X-RequestDigest"] = GetFormDigest();
restRequest.Headers["IF-MATCH"] = "*";
restRequest.Headers["X-Http-Method"] = "PATCH";
restRequest.Accept = "application/atom+xml";
restRequest.ContentType = "application/atom+xml";
restRequest.ContentLength = itemXML.Length;
StreamWriter sw = new StreamWriter(restRequest.GetRequestStream());
sw.Write(itemXML);
sw.Flush();
HttpWebResponse restResponse = (HttpWebResponse)restRequest.GetResponse();
}
Deleting items is a simple operation compared to the other methods. To delete an item, a URI is constructed that refers to the item to be deleted. A form digest is sent in the headers and the DELETE verb is used to indicate that the target item should be deleted. There is no XML chunk to create for this operation. Example 15 shows the implementation details for deleting items from the contacts list.
Example 15. Deleting items from a contacts list
public static void RemoveItem(string ID)
{
Uri uri = new Uri(AppWebUrl +
"/_api/web/lists/getByTitle('Contacts')/items(" + ID + ")");
HttpWebRequest restRequest = (HttpWebRequest)WebRequest.Create(uri);
restRequest.Credentials = CredentialCache.DefaultCredentials;
restRequest.Method = "DELETE";
restRequest.Headers["X-RequestDigest"] = GetFormDigest();
restRequest.Headers["IF-MATCH"] = "*";
restRequest.Accept = "application/atom+xml";
restRequest.ContentType = "application/atom+xml";
HttpWebResponse restResponse = (HttpWebResponse)restRequest.GetResponse();
}