Recently I was doing a POC to upload a bunch of documents programmatically to SharePoint Document Library using C# CSOM. Initially I was trying with the RestAPI provided by Microsoft and wanted to Share the entire steps to the readers. There are some other optimal faster ways are there. But again, this is the first approach tried. This is not the optimal solution. The issues, which we have in this approach and the easiest work around for that will be addressed on the upcoming article.
As usual, I was creating a Console application which will read the files from the file system and upload into the SharePoint using the RestAPI.
namespace Office365.Console
{
using Microsoft.SharePoint.Client;
using Newtonsoft.Json;
using System;
using System.Collections.Concurrent;
using System.IO;
using System.Net;
using System.Net.Http;
class Program
{
private static ConcurrentDictionary<Uri, RESTFormDigest> FormDigests { get; set; }
static void Main(string[] args)
{
UploadSmallerFiles();
System.Console.WriteLine("Completed");
System.Console.ReadLine();
}
static string siteUrl = "https://*****.sharepoint.com/sites/DeveloperSite/";
static string userName = "sathish@******.com";
static string password = "*********";
public async static void UploadSmallerFiles()
{
try
{
OfficeDevPnP.Core.AuthenticationManager authMgr = new OfficeDevPnP.Core.AuthenticationManager();
using (var ctx = authMgr.GetSharePointOnlineAuthenticatedContextTenant(siteUrl, userName, password))
{
Web web = ctx.Web;
ctx.Load(web);
ctx.Load(web.Lists);
ctx.ExecuteQueryRetry();
List list = web.Lists.GetByTitle("D1");
ctx.Load(list);
ctx.ExecuteQueryRetry();
Folder folder = list.RootFolder.EnsureFolder("Folder1");
ctx.Load(folder);
ctx.ExecuteQueryRetry();
var credentials = new SharePointOnlineCredentials(userName, OfficeDevPnP.Core.Utilities.EncryptionUtility.ToSecureString(password));
var targetUri = new Uri(siteUrl);
var rawCookie = (credentials.GetAuthenticationCookie(targetUri) ?? string.Empty).TrimStart("SPOIDCRL=".ToCharArray());
var CookieContainer = new CookieContainer();
CookieContainer.Add(new Cookie("FedAuth", rawCookie, string.Empty, targetUri.Authority));
CookieContainer.Add(new Cookie("SPOIDCRL", rawCookie, string.Empty, targetUri.Authority));
var clientHandler = new HttpClientHandler()
{
CookieContainer = CookieContainer,
UseCookies = true,
};
var client = new HttpClient(clientHandler);
client.BaseAddress = new Uri(siteUrl);
client.Timeout = TimeSpan.FromMinutes(60);
client.DefaultRequestHeaders.Add("Accept", @"application/json;odata=verbose");
client.DefaultRequestHeaders.Add("X-RequestDigest", GetFormRequestDigest(siteUrl));
string serverRelativeUrl = string.Empty;
var urlAddFile = string.Format("{0}/_api/web/GetFolderByServerRelativeUrl('{1}')/Files/Add(url='{2}',overwrite=true)", ctx.Web.Url, folder.ServerRelativeUrl, "SmallFile.txt");
var stream = System.IO.File.Open("D:\SmallFile.txt", System.IO.FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
var streamContent = new StreamContent(stream);
var response = await client.PostAsync(urlAddFile, streamContent);
}
}
catch (Exception ex) {
System.Console.WriteLine("Exception occurred : " + ex.Message);
System.Console.ReadLine();
}
}
private static string GetFormRequestDigest(string webUrl, Guid correlationId = new Guid())
{
HttpResponseMessage response = null;
try
{
var uri = new Uri(webUrl);
var credentials = new SharePointOnlineCredentials(userName, OfficeDevPnP.Core.Utilities.EncryptionUtility.ToSecureString(password));
var targetUri = new Uri(siteUrl);
var rawCookie = (credentials.GetAuthenticationCookie(targetUri) ?? string.Empty).TrimStart("SPOIDCRL=".ToCharArray());
var CookieContainer = new CookieContainer();
CookieContainer.Add(new Cookie("FedAuth", rawCookie, string.Empty, targetUri.Authority));
CookieContainer.Add(new Cookie("SPOIDCRL", rawCookie, string.Empty, targetUri.Authority));
var clientHandler = new HttpClientHandler()
{
CookieContainer = CookieContainer,
UseCookies = true,
};
var client = new HttpClient(clientHandler);
client.BaseAddress = new Uri(siteUrl);
client.Timeout = TimeSpan.FromMinutes(60);
client.DefaultRequestHeaders.Add("Accept", @"application/json;odata=verbose");
var url = string.Format("{0}/_api/contextinfo", webUrl);
using (var content = new StringContent(string.Empty))
{
response = client.PostAsync(url, content).Result;
}
response.EnsureSuccessStatusCode();
var data = response.Content.ReadAsStringAsync().Result;
var info = JsonConvert.DeserializeObject<dynamic>(data);
FormDigests = new ConcurrentDictionary<Uri, RESTFormDigest>();
FormDigests[uri] = new RESTFormDigest(Convert.ToString(info["d"]["GetContextWebInformation"]["FormDigestValue"]));
return FormDigests[uri].FormDigest;
}
catch (Exception ex)
{
return string.Empty;
}
}
}
}
The FormDigest Class looks below.
namespace Office365.Console
{
using System;
public class RESTFormDigest
{
public RESTFormDigest()
{
this.FormDigest = string.Empty;
this.Expiry = DateTime.MinValue;
}
public RESTFormDigest(string formDigest)
{
this.FormDigest = formDigest;
this.Expiry = DateTime.UtcNow.AddMinutes(20);
}
public string FormDigest { get; private set; }
public DateTime Expiry { get; private set; }
}
}
The limitation on the above method is, we cannot upload file more than 200 MB file. Even, when we try to upload, it does not throw any exception. But, the document was not uploading. Hence, we need to find a work around for that.
But one best thing is, this will execute asynchronously. When we are trying to upload a bunch of documents, then, even in our program, if we have not implemented the multi-threaded approach, the PostAsync method will move on to the next document. But, this is a bit complex to implement.
Happy Coding,
Sathish Nadarajan.
Leave a comment