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();
// Set body of the upload session request
CreateUploadSessionPostRequestBody uploadSessionRequest = new CreateUploadSessionPostRequestBody();
DriveItemUploadableProperties properties = new DriveItemUploadableProperties();
properties.getAdditionalData().put("@microsoft.graph.conflictBehavior", "replace");
uploadSessionRequest.setItem(properties);
// Create an upload session
// ItemPath does not need to be a path to an existing item
String myDriveId = graphClient.me().drive().get().getId();
UploadSession uploadSession = graphClient.drives()
.byDriveId(myDriveId)
.items()
.byDriveItemId("root:/"+itemPath+":")
.createUploadSession()
.post(uploadSessionRequest);
// Create the upload task
int maxSliceSize = 320 * 10;
LargeFileUploadTask<DriveItem> largeFileUploadTask = new LargeFileUploadTask<>(
graphClient.getRequestAdapter(),
uploadSession,
fileStream,
streamSize,
maxSliceSize,
DriveItem::createFromDiscriminatorValue);
int maxAttempts = 5;
// Create a callback used by the upload provider
IProgressCallback callback = (current, max) -> System.out.println(
String.format("Uploaded %d bytes of %d total bytes", current, max));
// Do the upload
try {
UploadResult<DriveItem> uploadResult = largeFileUploadTask.upload(maxAttempts, callback);
if (uploadResult.isUploadSuccessful()) {
System.out.println("Upload complete");
System.out.println("Item ID: " + uploadResult.itemResponse.getId());
} else {
System.out.println("Upload failed");
}
} catch (CancellationException ex) {
System.out.println("Error uploading: " + ex.getMessage());
}
// Create a file stream
$file = GuzzleHttp\Psr7\Utils::streamFor(fopen($filePath, 'r'));
// Create the upload session request
$uploadProperties = new Models\DriveItemUploadableProperties();
$uploadProperties->setAdditionalData([
'@microsoft.graph.conflictBehavior' => 'replace'
]);
// use Microsoft\Graph\Generated\Drives\Item\Items\Item\CreateUploadSession\CreateUploadSessionPostRequestBody
// as DriveItemCreateUploadSessionPostRequestBody;
$uploadSessionRequest = new DriveItemCreateUploadSessionPostRequestBody();
$uploadSessionRequest->setItem($uploadProperties);
// Create the upload session
/** @var Models\Drive $drive */
$drive = $graphClient->me()->drive()->get()->wait();
$uploadSession = $graphClient->drives()
->byDriveId($drive->getId())
->items()
->byDriveItemId('root:/'.$itemPath.':')
->createUploadSession()
->post($uploadSessionRequest)
->wait();
$largeFileUpload = new LargeFileUploadTask($uploadSession, $graphClient->getRequestAdapter(), $file);
$totalSize = $file->getSize();
$progress = fn($prog) => print('Uploaded '.$prog[1].' of '.$totalSize.' bytes'.PHP_EOL);
try {
$largeFileUpload->upload($progress)->wait();
} catch (\Psr\Http\Client\NetworkExceptionInterface $ex) {
$largeFileUpload->resume()->wait();
}
// 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
Message draftMessage = new Message();
draftMessage.setSubject("Large attachment");
Message savedDraft = graphClient.me().messages().post(draftMessage);
// Get an input stream for the file
File file = new File(filePath);
InputStream fileStream = new FileInputStream(file);
long streamSize = file.length();
final AttachmentItem largeAttachment = new AttachmentItem();
largeAttachment.setAttachmentType(AttachmentType.File);
largeAttachment.setName(file.getName());
largeAttachment.setSize(streamSize);
com.microsoft.graph.users.item.messages.item.attachments.createuploadsession.CreateUploadSessionPostRequestBody uploadRequestBody
= new com.microsoft.graph.users.item.messages.item.attachments.createuploadsession.CreateUploadSessionPostRequestBody();
uploadRequestBody.setAttachmentItem(largeAttachment);
final UploadSession uploadSession = graphClient.me()
.messages()
.byMessageId(savedDraft.getId())
.attachments()
.createUploadSession()
.post(uploadRequestBody);
LargeFileUploadTask<FileAttachment> largeFileUploadTask = new LargeFileUploadTask<>(
graphClient.getRequestAdapter(),
uploadSession,
fileStream,
streamSize,
FileAttachment::createFromDiscriminatorValue);
int maxAttempts = 5;
// Create a callback used by the upload provider
IProgressCallback callback = (current, max) -> System.out.println(
String.format("Uploaded %d bytes of %d total bytes", current, max));
// Do the upload
try {
UploadResult<FileAttachment> uploadResult = largeFileUploadTask.upload(maxAttempts, callback);
if (uploadResult.isUploadSuccessful()) {
System.out.println("Upload complete");
System.out.println("Item ID: " + uploadResult.itemResponse.getId());
} else {
System.out.println("Upload failed");
}
} catch (CancellationException ex) {
System.out.println("Error uploading: " + ex.getMessage());
}
// Create a message
$draftMessage = new Models\Message();
$draftMessage->setSubject('Large attachment');
/** @var Models\Message $savedDraft */
$savedDraft = $graphClient->me()
->messages()
->post($draftMessage)
->wait();
// Create a file stream
$file = GuzzleHttp\Psr7\Utils::streamFor(fopen($filePath, 'r'));
// Create an attachment
$attachment = new Models\AttachmentItem();
$attachment->setAttachmentType(new Models\AttachmentType(Models\AttachmentType::FILE));
$attachment->setName(basename($filePath));
$attachment->setSize($file->getSize());
// use Microsoft\Graph\Generated\Users\Item\Messages\Item\Attachments\CreateUploadSession\CreateUploadSessionPostRequestBody
// as AttachmentCreateUploadSessionPostRequestBody;
$uploadSessionRequest = new AttachmentCreateUploadSessionPostRequestBody();
$uploadSessionRequest->setAttachmentItem($attachment);
// Create the upload session
$uploadSession = $graphClient->me()
->messages()
->byMessageId($savedDraft->getId())
->attachments()
->createUploadSession()
->post($uploadSessionRequest)
->wait();
$largeFileUpload = new LargeFileUploadTask($uploadSession, $graphClient->getRequestAdapter(), $file);
$totalSize = $file->getSize();
$progress = fn($prog) => print('Uploaded '.$prog[1].' of '.$totalSize.' bytes'.PHP_EOL);
try {
$largeFileUpload->upload($progress)->wait();
} catch (\Psr\Http\Client\NetworkExceptionInterface $ex) {
$largeFileUpload->resume()->wait();
}
// 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}`);
Coming soon: Throughout 2024 we will be phasing out GitHub Issues as the feedback mechanism for content and replacing it with a new feedback system. For more information see: https://aka.ms/ContentUserFeedback.