Behavior:
When using the API to upload large documents, the following error message is shown;
"Exception 413 Request Entity Too Large"
Solution:
Please refer to the following guide on how to upload large files with .NET SDK or REST API;
.NET SDK
To upload large documents, the following method from DocuWare's Developer pages can be used to upload in chunks.
Easy Uploading Huge Files | DocuWare SDK Documentation.
REST API
A different approach will need to be taken when uploading large documents via the REST API.
Please refer to the example of how this could be accomplished;
using System.Net;
using RestSharp;
using System.IO;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
public static class ChunkUpload {
public static void RestSharpCallSequence()
{
string orgName = ""; // X in X.docuware.cloud
string userName = ""; //username to login with
string password = ""; //password
string fileCabinetID = ""; //file cabinet ID
string BaseUrl = "https://ORGNAME.docuware.com/DocuWare/Platform";
RestClient client = new RestClient(BaseUrl);
RestRequest request = new RestRequest($"{baseURL}/Account/Logon", Method.Post);
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddHeader("Accept", "application/json");
request.AddParameter("Organization", orgName);
request.AddParameter("UserName", userName);
request.AddParameter("Password", password);
request.AddParameter("RememberMe", "true");
RestResponse response = client.Execute(request);
//Capture cookie for use in next call
Cookie cookie = response.Cookies[1];
Console.WriteLine("Finished");
// Chunking Setup
chunkUpload(cookie, client);
}
public static void chunkUpload(Cookie cookie, RestClient restClient)
{
// Define the API base and file cabinet URLs
RestClient client = restClient;
string OrgName = ""; // X in X.docuware.cloud
string baseURL = $"https://{OrgName}.docuware.cloud";
string platformURL = $"{baseURL}/DocuWare/Platform";
string FileCabinetId = "98f77e6e-5a56-406e-a6d4-51ef7a37eda1";
// Set the Chunk Size - 10 MB was arbitrarily set here.
int ChunkSize = 10 * 1024 * 1024; // 10 MB
// Set the file path of the file to be uploaded
string filePath = $""; //should be changed to your filepath|
try
{
//Open the File Stream and get the file size, filename, and modification date.
FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
long totalFileSize = fileStream.Length;
string fileName = Path.GetFileName(filePath);
DateTime modificationDate = File.GetLastWriteTimeUtc(filePath);
// Set the endpoint URL and create a new RestRequest object with the POST method
string suffix = $"/FileCabinets/{FileCabinetId}/Documents/";
string url = $"{platformURL}/{suffix}";
var request = new RestRequest(url, Method.Post);
// Initialize variables for chunk uploading
string chunkReference = null;
int bytesUploaded = 0;
// Loop through the file and upload chunks
while (bytesUploaded < totalFileSize)
{
// Read a chunk of the file into a buffer
byte[] buffer = new byte[ChunkSize];
int bytesRead = fileStream.Read(buffer, 0, ChunkSize);
// Resize the buffer if the last chunk is less than the chunk size
if (bytesRead < ChunkSize)
{
Array.Resize(ref buffer, bytesRead);
}
// Set headers for the request
request.AddHeader("Content-Type", "application/octet-stream");
request.AddHeader("Content-Length", bytesRead.ToString());
request.AddHeader("Content-Disposition", $"inline; filename=\"{fileName}\"; modificationdate=\"{modificationDate:R}\"");
request.AddHeader("X-File-ModifiedDate", $"{modificationDate:R}");
request.AddHeader("X-File-Name", fileName);
request.AddHeader("X-File-Size", totalFileSize.ToString());
request.AddHeader("Cookie", cookie.ToString());
request.AddHeader("Expect", "100-continue");
// Add the chunk data to the request body
request.AddParameter("application/octet-stream", buffer, ParameterType.RequestBody);
// If this is not the first chunk, add the chunk reference and location headers to the request
if (!string.IsNullOrEmpty(chunkReference))
{
request.AddQueryParameter("loc", bytesUploaded.ToString());
request.AddQueryParameter("chunkReference", chunkReference);
}
// Set the base URL and add the cookie to the client
Uri baseUri = new Uri(platformURL);
client.CookieContainer.Add(cookie);
// Execute the chunk upload request
var response = client.Execute(request);
var deserializedJsonResponseBody = JsonConvert.DeserializeObject<IntermediateResponse>(response.Content.ToString());
// Check the response status code
if (response.StatusCode != HttpStatusCode.OK)
{
Console.WriteLine($"Unexpected status code: {response.StatusCode}");
Console.WriteLine("Error: Upload failed.");
return;
}
Console.WriteLine("Chunk Request Executed");
/* If there are more chunks to be uploaded, get the next URL from the response
* and create a new RestRequest object with the POST method for the next chunk
*/
if (bytesUploaded + bytesRead < totalFileSize)
{
// Deserialize the response JSON to get the next URL
url = baseURL + deserializedJsonResponseBody.FileChunk.Links[0].href;
request = new RestRequest(url, Method.Post);
}
else //for the last chunk, get the final deserialized response
{
var finalResposne = JsonConvert.DeserializeObject<JSON>(response.Content.ToString());
}
// Update the total bytes uploaded and print progress
bytesUploaded += bytesRead;
Console.WriteLine($"Uploaded {bytesUploaded} / {totalFileSize} bytes");
}
Console.WriteLine("File uploaded successfully.");
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
}
/*The below classes are for full deserialization of the JSON string responses.
* What are used in this is RootObject->FileChunk->Link->href[0], which grabs the "next" link.
*/
public class FileChunk
{
public List<Link> Links { get; set; }
public bool Finished { get; set; }
public string LastChunkId { get; set; }
public int BytesWritten { get; set; }
}
public class Link
{
public string rel { get; set; }
public string href { get; set; }
}
public class IntermediateResponse
{
public FileChunk FileChunk { get; set; }
public bool HaveMoreTotalPages { get; set; }
public bool HasTextAnnotation { get; set; }
public bool HasXmlDigitalSignatures { get; set; }
public bool AnnotationsPreview { get; set; }
public int TotalPages { get; set; }
public int Id { get; set; }
public bool LastModifiedSpecified { get; set; }
public bool CreatedAtSpecified { get; set; }
public int FileSize { get; set; }
public int SectionCount { get; set; }
public string IntellixTrust { get; set; }
public string VersionStatus { get; set; }
}
public class Section
{
public List<string> SignatureStatus { get; set; }
public Pages Pages { get; set; }
public Thumbnails Thumbnails { get; set; }
public List<Link> Links { get; set; }
public string Id { get; set; }
public string ContentType { get; set; }
public bool HaveMorePages { get; set; }
public int PageCount { get; set; }
public int FileSize { get; set; }
public string OriginalFileName { get; set; }
public string ContentModified { get; set; }
public bool HasTextAnnotation { get; set; }
public bool AnnotationsPreview { get; set; }
}
public class Pages
{
public List<object> Page { get; set; }
}
public class Thumbnails
{
public List<object> Page { get; set; }
}
public class JSON
{
public Guid FileCabinetId { get; set; }
public List<Field> Fields { get; set; }
public Flags Flags { get; set; }
public Version Version { get; set; }
public List<Link> Links { get; set; }
public List<Section> Sections { get; set; }
public string ContentType { get; set; }
public FileChunk FileChunk { get; set; }
public bool HaveMoreTotalPages { get; set; }
public bool HasTextAnnotation { get; set; }
public bool HasXmlDigitalSignatures { get; set; }
public bool AnnotationsPreview { get; set; }
public int TotalPages { get; set; }
public int Id { get; set; }
public string Title { get; set; }
public string LastModified { get; set; }
public bool LastModifiedSpecified { get; set; }
public string CreatedAt { get; set; }
public bool CreatedAtSpecified { get; set; }
public int FileSize { get; set; }
public int SectionCount { get; set; }
public string IntellixTrust { get; set; }
public string VersionStatus { get; set; }
}
public class Field
{
public bool SystemField { get; set; }
public string FieldName { get; set; }
public string FieldLabel { get; set; }
public bool IsNull { get; set; }
public bool ReadOnly { get; set; }
public object Item { get; set; }
public string ItemElementName { get; set; }
}
public class Flags
{
public bool IsCold { get; set; }
public bool IsDBRecord { get; set; }
public bool IsCheckedOut { get; set; }
public bool IsCopyRightProtected { get; set; }
public bool IsVoiceAvailable { get; set; }
public bool HasAppendedDocuments { get; set; }
public bool IsProtected { get; set; }
public bool IsDeleted { get; set; }
public bool IsEmail { get; set; }
}
}