A number of 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.
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}");
}
// Get an input stream for the file
File file = new File(filePath);
InputStream fileStream = new FileInputStream(file);
long streamSize = file.length();
final DriveItemCreateUploadSessionParameterSet uploadParams = DriveItemCreateUploadSessionParameterSet
.newBuilder().withItem(new DriveItemUploadableProperties()).build();
// Create an upload session
final UploadSession uploadSession = graphClient.me().drive().root()
.itemWithPath(itemPath).createUploadSession(uploadParams).buildRequest()
.post();
if (null == uploadSession) {
fileStream.close();
throw new Exception("Could not create upload session");
}
// Create a callback used by the upload provider
final IProgressCallback callback = new IProgressCallback() {
@Override
// Called after each slice of the file is uploaded
public void progress(final long current, final long max) {
System.out.println(
String.format("Uploaded %d bytes of %d total bytes", current, max));
}
};
LargeFileUploadTask<DriveItem> largeFileUploadTask = new LargeFileUploadTask<DriveItem>(
uploadSession, graphClient, fileStream, streamSize, DriveItem.class);
// Do the upload
largeFileUploadTask.upload(0, null, callback);
// readFile from fs/promises
const file = await readFile(filePath);
// basename from path
const fileName = basename(filePath);
const options: OneDriveLargeFileUploadOptions = {
// Relative path from root folder
path: targetFolderPath,
fileName: fileName,
rangeSize: 1024 * 1024,
uploadEventHandlers: {
// Called as each "slice" of the file is uploaded
progress: (range, _) => {
console.log(`Uploaded bytes ${range?.minValue} to ${range?.maxValue}`);
},
},
};
// Create FileUpload object
const fileUpload = new FileUpload(file, fileName, file.byteLength);
// Create a OneDrive upload task
const uploadTask = await OneDriveLargeFileUploadTask.createTaskWithFileObject(
graphClient,
fileUpload,
options
);
// Do the upload
const uploadResult: UploadResult = await uploadTask.upload();
// The response body will be of the corresponding type of the
// item being uploaded. For OneDrive, this is a DriveItem
const driveItem = uploadResult.responseBody as DriveItem;
console.log(`Uploaded file with ID: ${driveItem.id}`);
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.
// 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);
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}");
}
// Create message
final Message draftMessage = new Message();
draftMessage.subject = "Large attachment";
final Message savedDraft = graphClient.me().messages().buildRequest()
.post(draftMessage);
// Get an input stream for the file
File file = new File(filePath);
InputStream fileStream = new FileInputStream(file);
final AttachmentItem largeAttachment = new AttachmentItem();
largeAttachment.attachmentType = AttachmentType.FILE;
largeAttachment.name = file.getName();
largeAttachment.size = file.length();
final AttachmentCreateUploadSessionParameterSet uploadParams = AttachmentCreateUploadSessionParameterSet
.newBuilder().withAttachmentItem(largeAttachment).build();
final String draftId = savedDraft.id;
if (null == draftId) {
fileStream.close();
throw new Exception("");
}
final UploadSession uploadSession = graphClient.me().messages(draftId)
.attachments().createUploadSession(uploadParams).buildRequest().post();
if (null == uploadSession) {
fileStream.close();
throw new Exception("Could not create upload session");
}
// Create a callback used by the upload provider
final IProgressCallback callback = new IProgressCallback() {
@Override
// Called after each slice of the file is uploaded
public void progress(final long current, final long max) {
System.out.println(
String.format("Uploaded %d bytes of %d total bytes", current, max));
}
};
LargeFileUploadTask<FileAttachment> uploadTask = new LargeFileUploadTask<FileAttachment>(
uploadSession, graphClient, fileStream, file.length(), FileAttachment.class);
// Do the upload
uploadTask.upload(0, null, callback);
// readFile from fs/promises
const file = await readFile(filePath);
// basename from path
const fileName = basename(filePath);
const options: LargeFileUploadTaskOptions = {
rangeSize: 1024 * 1024,
uploadEventHandlers: {
// Called as each "slice" of the file is uploaded
progress: (range, _) => {
console.log(`Uploaded bytes ${range?.minValue} to ${range?.maxValue}`);
},
},
};
// Create a draft message
const message: Message = await graphClient.api('/me/messages').post({
subject: 'Large file attachment',
});
// Create upload session using draft message's ID
const uploadUrl = `/me/messages/${message.id}/attachments/createUploadSession`;
const uploadSession = await LargeFileUploadTask.createUploadSession(
graphClient,
uploadUrl,
{
AttachmentItem: {
attachmentType: 'file',
name: fileName,
size: file.byteLength,
},
}
);
// Create file upload
const fileUpload = new FileUpload(file, fileName, file.byteLength);
// Create upload task
const uploadTask = new LargeFileUploadTask(
graphClient,
fileUpload,
uploadSession,
options
);
// Upload the file
const uploadResult = await uploadTask.upload();
console.log(`File uploaded to ${uploadResult.location}`);