In the previous
article we saw how to get data from SharePoint into a console application.
In this article we will see how to post data into SharePoint using a console
application. Basically the idea is that, without referencing a SharePoint
library, you can read and write data into SharePoint if the user whose
credentials are passed has those rights on SharePoint. When getting data you use
the GET verb and when writing data you use the POST verb. In some cases this
POST verb can be overridden by adding an X-HTTP-Method header to the request and
specifying a value of PUT, MERGE or DELETE.
In general, POST is used when you're creating a SharePoint object, such as a
site, folder, file, list or list item. MERGE is used when you're editing certain
properties of a SharePoint object and you want the other properties to keep
their current values. PUT is used when you want to replace a SharePoint object.
DELETE is used when you want to delete a SharePoint object.
In this example, let us consider that we want to create a new folder in a Shared
documents library in a team site. To get a list of all folders you can type "<site_url>/_api/web/folders"
in the browser and you will see XML that will have an id of each folder in that
site. For example "<<Site URL>>/sites/ts/_api/web/folders" gives me data as
shown in the screen below.
Let's create a new folder called "Folder Created From Code". The important
elements are the method types (X-Http-Method) and setting of headers. Let's see
the details on the headers.
Every request that writes to SharePoint must include a form digest. You can
retrieve the form digest value by making a POST request with an empty body to
the "http://site url/_api/contextinfo"
and extracting the value of the FormDigestValue. For example: the following
screenshot shows the FormDigestValue that is returned in my case.
To retrieve the form digest, simple string operations are used as shown below:
// Get the FormDigest Value
var
startTag =
"FormDigestValue";
var
endTag =
"LibraryVersion";
var
startTagIndex = results.IndexOf(startTag)+1;
var
endTagIndex = results.IndexOf(endTag, startTagIndex);
string
newFormDigest =
null;
if
((startTagIndex >= 0) && (endTagIndex > startTagIndex))
{
newFormDigest = results.Substring(startTagIndex +
startTag.Length+2, endTagIndex - startTagIndex - startTag.Length-5);
}
In all subsequent POST requests, you add an X-RequestDigest
header with the digest as its value as shown below.
String
digestRequest =
"<<Site URL>>/sites/ts/_api/Web/folders";
HttpWebRequest
spNewRequest = (HttpWebRequest)HttpWebRequest.Create(digestRequest);
CredentialCache
credNewCache =
new
CredentialCache();
credNewCache.Add(new
Uri(digestRequest),
"NTLM",
CredentialCache.DefaultNetworkCredentials);
spNewRequest.Credentials = credNewCache;
spNewRequest.Method =
"POST";
spNewRequest.Accept =
"application/json;odata=verbose";
spNewRequest.ContentType =
"application/json;odata=verbose";
spNewRequest.Headers.Add("X-RequestDigest",
newFormDigest);
Content Length is another important header
that needs to be set. If not set then the error is thrown as shown in the screen
below.
string
listPostBody =
"{'__metadata':{'type':'SP.Folder'}, 'ServerRelativeUrl':'/sites/ts/Shared
Documents/Folder Created From Code'}";
// For Content Length
byte[]
postByte =
Encoding.UTF8.GetBytes(listPostBody);
spNewRequest.ContentLength = postByte.Length;
Stream
postStreamBody = spNewRequest.GetRequestStream();
postStreamBody.Write(postByte, 0, postByte.Length);
postStreamBody.Close();
The complete code is as below. Please note
that this is only sample code without adding verifications and exceptions.
Please do not use in production as-is; only for PoC purposes. Replace "<<Site
URL>>" with your site URL.
static
void
Main(string[]
args)
{
//
1st request to get the context information
string
formdigestRequest =
"<<Site URL>>/sites/ts/_api/contextinfo";
CredentialCache
credCache =
new
CredentialCache();
credCache.Add(new
Uri(formdigestRequest),
"NTLM",
CredentialCache.DefaultNetworkCredentials);
HttpWebRequest
spRequest = (HttpWebRequest)HttpWebRequest.Create(formdigestRequest);
spRequest.Credentials = credCache;
spRequest.Method =
"POST";
spRequest.Accept =
"application/json;odata=verbose";
spRequest.ContentLength = 0;
Stream
postStream;
HttpWebResponse
endpointResponse = (HttpWebResponse)spRequest.GetResponse();
string
results = GetHTTPResponse(endpointResponse,
out
postStream,
out
results);
// Get the FormDigest Value
var
startTag =
"FormDigestValue";
var
endTag =
"LibraryVersion";
var
startTagIndex = results.IndexOf(startTag)+1;
var
endTagIndex = results.IndexOf(endTag, startTagIndex);
string
newFormDigest =
null;
if
((startTagIndex >= 0) && (endTagIndex > startTagIndex))
{
newFormDigest = results.Substring(startTagIndex +
startTag.Length+2, endTagIndex - startTagIndex - startTag.Length-5);
}
String
digestRequest =
"<<Site URL>>/sites/ts/_api/Web/folders";
HttpWebRequest
spNewRequest = (HttpWebRequest)HttpWebRequest.Create(digestRequest);
CredentialCache
credNewCache =
new
CredentialCache();
credNewCache.Add(new
Uri(digestRequest),
"NTLM",
CredentialCache.DefaultNetworkCredentials);
spNewRequest.Credentials = credNewCache;
spNewRequest.Method =
"POST";
spNewRequest.Accept =
"application/json;odata=verbose";
spNewRequest.ContentType =
"application/json;odata=verbose";
spNewRequest.Headers.Add("X-RequestDigest",
newFormDigest);
string
listPostBody =
"{'__metadata':{'type':'SP.Folder'}, 'ServerRelativeUrl':'/sites/ts/Shared
Documents/Folder Created From Code'}";
// For Content Length
byte[]
postByte =
Encoding.UTF8.GetBytes(listPostBody);
spNewRequest.ContentLength = postByte.Length;
Stream
postStreamBody = spNewRequest.GetRequestStream();
postStreamBody.Write(postByte, 0, postByte.Length);
postStreamBody.Close();
HttpWebResponse
webResponse = (HttpWebResponse)spNewRequest.GetResponse();
results = GetHTTPResponse(webResponse,
out
postStream,
out
results);
}
private
static
String
GetHTTPResponse(HttpWebResponse
endpointResponse,
out
Stream
postStream,
out
string
results)
{
postStream = endpointResponse.GetResponseStream();
StreamReader
postReader =
new
StreamReader(postStream);
results = postReader.ReadToEnd();
postReader.Close();
postStream.Close();
return
results;
}
You will see results, a new folder added, under the Shared Documents folder as
below.
In the next article, we will see how to edit and delete SharePoint objects and
items from applications without referencing SharePoint libraries.