Today I will be covering the steps you will need to upload files to a Sharepoint Online Document library using the Microsoft Graph API. If you haven’t read my previous article on getting started with the MS Graph API please take a moment to do so: Getting Started with the Microsoft Graph API

The content in this article follows on from the functions I have created in this previous article.

Let’s get started…

First thing I should mention is that this will be a combination of Sharepoint and OneDrive function calls within the Graph API. This is because Microsoft seemingly treats Sharpoint documents as components on a OneDrive repository.

Secondly, the design process is as follows:

a. Get the Sharepoint Site ID

b. Get the Sharepoint Folder ID

c. Get the Sharepoint Document Library ID

d. Upload the file to the Document Library.

Your client application will look something like this:

        private void UploadToSharepoint(byte[] htmlbytes)
        {
            try
            {
                using (var client = new WebClient())
                {
                    // Get the common SP properties first
                    var SPProperties = InitialiseMSGraphSharePoint();

                    // Get the Doc Library/Drive Ids
                    var url = string.Format(CORPORATESERVICEAPI + "msgraph/GetSharepointDocumentLibraries?SiteId={0}", SPProperties.SiteId);
                    var response = client.DownloadString(new Uri(url));
                    var JsonResponse = JObject.Parse(response);

                    if (Convert.ToString(JsonResponse.esError.Type) != "S")
                    {
                        throw new Exception("Error getting SharePoint Doc Library list.");
                    }
                    var driveCollectin = Convert.ToString(JsonResponse.DriveCollection);
                    JArray list = JArray.Parse(driveCollectin);

                    string DocumentFolderId = null;
                    DocumentFolderId = list.ToList().Where(i => i.SelectToken("Name").ToString() == "Documents").First().SelectToken("Id").ToString();

                    // Upload file to Doc Library under a specified folder path
                    try
                    {
                        url = string.Format(CORPORATESERVICEAPI + "msgraph/UploadDocumentLibraryFile");

                        requestData = new System.Dynamic.ExpandoObject();
                        requestData.SiteId = SPProperties.SiteId;
                        requestData.DriveId = DocumentFolderId;
                        requestData.FolderPath = "/";
                        requestData.FileName = "[[filename]]";
                        requestData.FileData = Convert.ToBase64String(htmlbytes);

                        client.Headers.Add("Content-Type", "Application/JSON");
                        response = client.UploadString(new Uri(url), "POST", Newtonsoft.Json.JsonConvert.SerializeObject(requestData));
                        JsonResponse = JObject.Parse(response);

                        if (Convert.ToString(JsonResponse.esError.Type) != "S")
                        {
                            Common.Manager.LoggingManager.Instance.Error(Convert.ToString(JsonResponse.esError.Message));
                        }
                    }
                    catch (Exception ex)
                    {
                        Common.Manager.LoggingManager.Instance.Error("Error uploading file: " + requestData.FileName + " to folder: " + requestData.FolderPath + ". " + ex.Message, ex);
                    }
                }

            }
            catch (Exception ex)
            {
                Common.Manager.LoggingManager.Instance.Error(ex.Message, ex);
                throw new Exception("Error uploading files to Sharepoint.", ex);
            }
        }

Here is the function called InitialiseMSGraphSharePoint(). Which is used to preset some Sharepoint values obtained from the Graph API.

        public Common.Entity.MSGraphSharePointProperties InitialiseMSGraphSharePoint()
        {
            var SPProperties = new Common.Entity.MSGraphSharePointProperties();

            using (var client = new WebClient())
            {
                // Get the Sharepoint Site ID
                var url = CORPORATESERVICEAPI
                            + "msgraph/GetSharepointSiteId"
                            + "?SharePointURL=" + System.Configuration.ConfigurationManager.AppSettings["SharePoint_SiteId"]
                            + "&SitePath=" + System.Configuration.ConfigurationManager.AppSettings["SharePoint_SitePath"];

                var response = client.DownloadString(new Uri(url));
                dynamic JsonResponse = JObject.Parse(response);

                if (Convert.ToString(JsonResponse.esError.Type) != "S")
                {
                    throw new Exception("Error getting Sharepoint Site Id.");
                }
                SPProperties.SiteId = Convert.ToString(JsonResponse.Id);

                // Get the SharePoint Folder ID
                url = string.Format(CORPORATESERVICEAPI + "msgraph/GetSharepointFolderId?SiteId={0}&FolderPath=/", SPProperties.SiteId);
                response = client.DownloadString(new Uri(url));
                JsonResponse = JObject.Parse(response);

                if (Convert.ToString(JsonResponse.esError.Type) != "S")
                {
                    throw new Exception("Error getting Sharepoint Folder Id.");
                }
                SPProperties.FolderId = Convert.ToString(JsonResponse.Id);
            }

            return SPProperties;
        }


The above client side code assumes that you have what I call a Corporate Services API hosted somewhere. The Corporate Services API is what submits the requests to the MS Graph API to obtain the necessary response data.

Below are all the required functions declared in the Corporate Services API:

Step A – Get the Sharepoint Site ID

        public async Task<HttpResponseMessage> GetSharepointSiteId([FromUri] Entity.GetSharepointSiteIdRequestData RequestData)
        {
            var respMessage = new HttpResponseMessage();
            var resp = new Entity.GetSharepointFolderIdResponse();

            try
            {
                string accessToken = await this.GetToken();
                string endpoint = string.Format(@"https://graph.microsoft.com/v1.0/sites/{0}:{1}", RequestData.SharePointURL, RequestData.SitePath);

                using (var client = new HttpClient())
                {
                    using (var request = new HttpRequestMessage(new HttpMethod("GET"), endpoint))
                    {
                        request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                        request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);

                        using (var response = await client.SendAsync(request))
                        {
                            respMessage.StatusCode = response.StatusCode;
                            if (response.IsSuccessStatusCode)
                            {
                                var json = JObject.Parse(await response.Content.ReadAsStringAsync());
                                var id = json.GetValue("id").ToString();

                                resp.SetEsError(new Entity.EsError("S", response.ReasonPhrase));
                                resp.Id = id;
                            }
                            else
                            {
                                resp.SetEsError(new Entity.EsError("E", response.ReasonPhrase));

                            }

                        }
                    }
                }
            }
            catch (Exception ex)
            {
                respMessage.StatusCode = HttpStatusCode.BadRequest;
                resp.SetEsError(new Entity.EsError("E", ex.Message));
            }
            respMessage.Content = new StringContent(JsonConvert.SerializeObject(resp));
            return respMessage;
        }


Step B – Get the Sharepoint Folder ID

        public async Task<HttpResponseMessage> GetSharepointFolderId([FromUri] Entity.GetSharepointFolderIdRequestData RequestData)
        {
            var respMessage = new HttpResponseMessage();
            var resp = new Entity.GetSharepointFolderIdResponse();

            try
            {
                string accessToken = await this.GetToken();
                string endpoint = string.Format(@"https://graph.microsoft.com/v1.0/sites/{0}/drive/root:/{1}", RequestData.SiteId, RequestData.FolderPath);

                using (var client = new HttpClient())
                {
                    using (var request = new HttpRequestMessage(new HttpMethod("GET"), endpoint))
                    {
                        request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                        request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);

                        using (var response = await client.SendAsync(request))
                        {
                            respMessage.StatusCode = response.StatusCode;
                            if (response.IsSuccessStatusCode)
                            {
                                var json = JObject.Parse(await response.Content.ReadAsStringAsync());
                                var id = json.GetValue("id").ToString();

                                resp.SetEsError(new Entity.EsError("S", response.ReasonPhrase));
                                resp.Id = id;
                            }
                            else
                            {
                                resp.SetEsError(new Entity.EsError("E", response.ReasonPhrase));

                            }

                        }
                    }
                }
            }
            catch (Exception ex)
            {
                respMessage.StatusCode = HttpStatusCode.BadRequest;
                resp.SetEsError(new Entity.EsError("E", ex.Message));
            }
            respMessage.Content = new StringContent(JsonConvert.SerializeObject(resp));
            return respMessage;
        }


Step C – Get the Sharepoint Document Library ID

        public async Task<HttpResponseMessage> GetSharepointDocumentLibraries([FromUri] Entity.GetSharepointDocumentLibrariesRequestData RequestData)
        {
            var respMessage = new HttpResponseMessage();
            var resp = new Entity.GetSharepointDocumentLibrariesResponse();

            try
            {
                string accessToken = await this.GetToken();
                string endpoint = string.Format(@"https://graph.microsoft.com/v1.0/sites/{0}/drives", RequestData.SiteId);

                using (var client = new HttpClient())
                {
                    using (var request = new HttpRequestMessage(new HttpMethod("GET"), endpoint))
                    {
                        request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                        request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);

                        using (var response = await client.SendAsync(request))
                        {
                            respMessage.StatusCode = response.StatusCode;
                            if (response.IsSuccessStatusCode)
                            {
                                var json = JObject.Parse(await response.Content.ReadAsStringAsync());
                                var docLibCollection = json["value"].ToList();
                                docLibCollection.ForEach(i =>
                                {
                                    resp.DriveCollection.Add(new Entity.Drive() { Id = i["id"].ToString(), Name = i["name"].ToString() });
                                });
                                resp.SetEsError(new Entity.EsError("S", response.ReasonPhrase));
                            }
                            else
                            {
                                resp.SetEsError(new Entity.EsError("E", response.ReasonPhrase));

                            }

                        }
                    }
                }
            }
            catch (Exception ex)
            {
                respMessage.StatusCode = HttpStatusCode.BadRequest;
                resp.SetEsError(new Entity.EsError("E", ex.Message));
            }
            respMessage.Content = new StringContent(JsonConvert.SerializeObject(resp));
            return respMessage;
        }


Step D – Upload the file to the Document Library

        [HttpPost]
        public async Task<HttpResponseMessage> UploadDocumentLibraryFile([FromBody]Entity.DocumentLibraryUploadRequestData RequestData)
        {
            var respMessage = new HttpResponseMessage();
            var resp = new Entity.DocumentLibraryUploadResponse();

            try
            {
                // Check if folder exists, if not, throw error.
                // This is because the Graph API will auto create the folder path if it does not exist.
                // This prevents typing errors creating an incorrect/adhoc folder structure.
                var folderCheckResponse = await this.GetSharepointFolderId(new Entity.GetSharepointFolderIdRequestData()
                {
                    SiteId = RequestData.SiteId,
                    FolderPath = RequestData.FolderPath
                });

                if (!folderCheckResponse.IsSuccessStatusCode)
                {
                    respMessage.StatusCode = folderCheckResponse.StatusCode;
                    resp.SetEsError(new Entity.EsError("E", folderCheckResponse.ReasonPhrase));

                    respMessage.Content = new StringContent(JsonConvert.SerializeObject(resp));
                    return respMessage;
                }


                // Folder path exists, continue with upload.
                string accessToken = await this.GetToken();

                using (var client = new HttpClient())
                {
                    string endpoint = string.Format(@"https://graph.microsoft.com/v1.0/sites/{0}/drives/{1}/root:/{2}/{3}:/createUploadSession", RequestData.SiteId, RequestData.DriveId, RequestData.FolderPath, RequestData.FileName);

                    var uploadURL = string.Empty;

                    using (var request = new HttpRequestMessage(new HttpMethod("PUT"), endpoint))
                    {
                        request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                        request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);

                        using (var response = await client.SendAsync(request))
                        {
                            var json = JObject.Parse(await response.Content.ReadAsStringAsync());
                            if (response.IsSuccessStatusCode)
                            {
                                uploadURL = json.GetValue("uploadUrl").ToString();
                            }
                            else
                            {
                                respMessage.StatusCode = response.StatusCode;
                                try
                                {
                                    var msg = JObject.Parse(json.GetValue("error").ToString()).GetValue("message").ToString();
                                    resp.SetEsError(new Entity.EsError("E", msg));
                                }
                                catch (Exception ex)
                                {
                                    resp.SetEsError(new Entity.EsError("E", "Could not create MS Graph upload session."));
                                }

                                respMessage.Content = new StringContent(JsonConvert.SerializeObject(resp));
                                return respMessage;
                            }
                        }
                    }

                    if (string.IsNullOrEmpty(uploadURL))
                    {
                        respMessage.StatusCode = HttpStatusCode.BadRequest;
                        resp.SetEsError(new Entity.EsError("E", "Upload session URL cannot be empty."));

                        respMessage.Content = new StringContent(JsonConvert.SerializeObject(resp));
                        return respMessage;
                    }


                    Byte[] byteArray = Convert.FromBase64String(RequestData.FileData);

                    long position = 0;
                    long totalLength = byteArray.LongLength;
                    int bytesPerPacket = MSGraph_SharepointBytesPerPacket;

                    while (true)
                    {
                        if (position + bytesPerPacket > byteArray.LongLength)
                        {
                            bytesPerPacket = (int)(byteArray.LongLength - position);
                        }

                        // Get a fragment of the entire byte array to upload
                        byte[] bytes = new byte[bytesPerPacket];
                        Buffer.BlockCopy(byteArray, (int)position, bytes, 0, bytesPerPacket);
                        var bytesRead = bytes.LongLength;

                        // If bytesRead == 0, then entire file has been transferrred
                        if (bytesRead == 0)
                        {
                            break;
                        }

                        // Upload a fragment of the file
                        await UploadFileFragmentAsync(bytes, uploadURL, position, totalLength);

                        position += bytesRead;
                    }

                    resp.SetEsError(new Entity.EsError("S", "Upload successful"));
                }
            }
            catch (Exception ex)
            {
                respMessage.StatusCode = HttpStatusCode.BadRequest;
                resp.SetEsError(new Entity.EsError("E", ex.Message));
            }
            respMessage.Content = new StringContent(JsonConvert.SerializeObject(resp));
            return respMessage;

        }

        private async Task<Boolean> UploadFileFragmentAsync(byte[] datas, string uploadUri, long position, long totalLength)
        {
            var client = new HttpClient();

            var request = new HttpRequestMessage(new HttpMethod("PUT"), uploadUri);

            request.Content = new ByteArrayContent(datas);
            request.Content.Headers.Add("Content-Length", datas.Length.ToString());

            //request.Content.Headers.Add("Content-Range", $"bytes {position}-{position + datas.Length - 1}/{totalLength}");
            request.Content.Headers.Add("Content-Range", string.Format("bytes {0}-{1}/{2}", position, position + datas.Length - 1, totalLength));

            using (var response = await client.SendAsync(request))
            {
                if (!response.IsSuccessStatusCode)
                {
                    throw new Exception(response.ReasonPhrase);
                }
            }

            return true;
        }

I hope everything is making sense up until this point.

The final note I wish to say is that the function UploadFileFragmentAsync() declared above, is used to upload the file in small chunks.

This allows relatively large files to be upload to the Sharepoint Document library via the Graph API, with the ability to resume failed transfers and pick up where you left off.

If you have any questions, please let me know!

Hope this helps 🙂