Upload large files using the Microsoft Graph SDKs

Many entities in Microsoft Graph support resumable file uploads to make it easier to upload large files. Instead of trying to upload the entire file in a single request, the file is sliced into smaller pieces and a request is used to upload a single slice. In order to simplify this process, the Microsoft Graph SDKs implement a large file upload task that manages the uploading of the slices.

Upload large file to OneDrive

using var fileStream = File.OpenRead(filePath);

// Use properties to specify the conflict behavior
// using DriveUpload = Microsoft.Graph.Drives.Item.Items.Item.CreateUploadSession;
var uploadSessionRequestBody = new DriveUpload.CreateUploadSessionPostRequestBody
{
    Item = 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 myDrive = await graphClient.Me.Drive.GetAsync();
var uploadSession = await graphClient.Drives[myDrive?.Id]
    .Items["root"]
    .ItemWithPath(itemPath)
    .CreateUploadSession
    .PostAsync(uploadSessionRequestBody);

// Max slice size must be a multiple of 320 KiB
int maxSliceSize = 320 * 1024;
var fileUploadTask = new LargeFileUploadTask<DriveItem>(
    uploadSession, fileStream, maxSliceSize, graphClient.RequestAdapter);

var totalLength = fileStream.Length;
// Create a callback that is invoked after each slice is uploaded
IProgress<long> progress = new Progress<long>(prog =>
{
    Console.WriteLine($"Uploaded {prog} bytes of {totalLength} bytes");
});

try
{
    // Upload the file
    var uploadResult = await fileUploadTask.UploadAsync(progress);

    Console.WriteLine(uploadResult.UploadSucceeded ?
        $"Upload complete, item ID: {uploadResult.ItemResponse.Id}" :
        "Upload failed");
}
catch (ODataError ex)
{
    Console.WriteLine($"Error uploading: {ex.Error?.Message}");
}

Resuming a file upload

The Microsoft Graph SDKs support resuming in-progress uploads. If your application encounters a connection interruption or a 5.x.x HTTP status during upload, you can resume the upload.

await fileUploadTask.ResumeAsync(progress);

Upload large attachment to Outlook message

// Create message
var draftMessage = new Message
{
    Subject = "Large attachment",
};

var savedDraft = await graphClient.Me
    .Messages
    .PostAsync(draftMessage);

using var fileStream = File.OpenRead(filePath);
var largeAttachment = new AttachmentItem
{
    AttachmentType = AttachmentType.File,
    Name = Path.GetFileName(filePath),
    Size = fileStream.Length,
};

// using AttachmentUpload = Microsoft.Graph.Me.Messages.Item.Attachments.CreateUploadSession;
var uploadSessionRequestBody = new AttachmentUpload.CreateUploadSessionPostRequestBody
{
    AttachmentItem = largeAttachment,
};

var uploadSession = await graphClient.Me
    .Messages[savedDraft?.Id]
    .Attachments
    .CreateUploadSession
    .PostAsync(uploadSessionRequestBody);

// Max slice size must be a multiple of 320 KiB
int maxSliceSize = 320 * 1024;
var fileUploadTask =
    new LargeFileUploadTask<FileAttachment>(uploadSession, fileStream, maxSliceSize, graphClient.RequestAdapter);

var totalLength = fileStream.Length;
// Create a callback that is invoked after each slice is uploaded
IProgress<long> progress = new Progress<long>(prog =>
{
    Console.WriteLine($"Uploaded {prog} bytes of {totalLength} bytes");
});

try
{
    // Upload the file
    var uploadResult = await fileUploadTask.UploadAsync(progress);
    Console.WriteLine(uploadResult.UploadSucceeded ? "Upload complete" : "Upload failed");
}
catch (ODataError ex)
{
    Console.WriteLine($"Error uploading: {ex.Error?.Message}");
}