I have an application that uploads a file to Sharepoint Online. It is using the MS Graph API, and using the Large File upload process (segmented file uploading).
It works fine from most of my machines, but when run on the test server it fails about 80% of the time, and fails pretty much 100% of the time when I run it on the main server (which is of course where it needs to run.)
The failure occurs when the API attempts to negotiate an HTTPS connection to the sharepoint site. The initial HTTP TLS Hello message gets a "connection closed by remote host".
If this was all the time I'd wonder if it was a missing certificate, or an invalid or missing cipher, but we get a success 20% of the time and the Hello message is identical (according to Fiddler analysis).
Our sharepoint support has dead-catted it here "We don't provide support for graph API" etc. and while I don't think the problem is with the graph API at all, I figure it's worth me asking if anyone else has experienced this problem, or has any ideas what could be causing it?
My current best guess is some sort of rate-limiting in the Sharepoint Server that is saying "too many file uploads in too short a time" This would seem odd though as we are test running it about once a minute. Maybe there are other jobs running on the server I'm not aware of.
Any way - If anyone can advise what the issue might be, please let me know.
In case it's relevant, here is the code that is performing the operation.
/// <summary>
/// Write a long stream out to the drive using the filename and path.
/// It avoids the limit of approx. 4Mb, so use this for larger files.
/// </summary>
/// <param name="data">The stream to write out to the file</param>
/// <param name="fileName">The target filename and path of the file</param>
/// <returns>The file ID or null on failure</returns>
/// <exception>Can throw exceptions if the file doesn't exist or the write fails</exception>
public async Task<string> WriteLongStreamAsFileAsync(Stream data, string fileName)
{
var uploadProps = new DriveItemUploadableProperties
{
AdditionalData = new Dictionary<string, object>
{
{ "@microsoft.graph.conflictBehavior", "replace" }
}
};
// Create the upload session
// itemPath does not need to be a path to an existing item
var uploadSession = await BaseDrive().Root
.ItemWithPath(fileName)
.CreateUploadSession(uploadProps)
.Request()
.PostAsync();
// Max slice size must be a multiple of 320 KiB
int maxSliceSize = 320 * 1024;
var fileUploadTask =
new LargeFileUploadTask<DriveItem>(uploadSession, data, maxSliceSize);
long? totalLength = null;
try
{
totalLength = data.Length;
}
catch (Exception) { /* absorb all errors. not all streams support Length */}
// Create a callback that is invoked after each slice is uploaded
IProgress<long> progress = new Progress<long>(prog => {
var message = $"Uploaded {prog} bytes of {totalLength} bytes";
logger.Debug(message);
});
// Upload the file
var uploadResult = await fileUploadTask.UploadAsync(progress);
var resultMessage = (uploadResult?.UploadSucceeded == true) ?
$"Upload complete, item ID: {uploadResult.ItemResponse.Id}" :
"Upload failed";
logger.Info(resultMessage);
var x = uploadResult?.ItemResponse;
return x?.Id;
}