I am trying to upload files to OneDrive using Graph API. The below code works fine when I upload files with size lesser than 4MB but it shows an error when I try to upload files more than 4 MB. I went through this documentation but still, I am not sure how can I get this work.
Below is my working code for files less than 4MB.
using (var client = new HttpClient())
{
var url = "https://graph.microsoft.com/v1.0" + $"/drives/{driveID}/items/{folderId}:/{originalFileName}:/content";
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + GetAccessToken());
byte[] sContents = System.IO.File.ReadAllBytes(filePath);
var content = new ByteArrayContent(sContents);
var response = client.PutAsync(url, content).Result.Content.ReadAsStringAsync().Result;
}
Please help
You can add files and folders to OneDrive automatically from your PC without having to go to the OneDrive website. Files you add to OneDrive this way can be up to 250GB in size. (If you sign in with a work or school account, the maximum file size is 15GB.)
We need to split the byte array by length (i.e. 4MB) and pass them to the OneDrive API. The working version is below:
using (var client = new HttpClient())
{
var url = "https://graph.microsoft.com/v1.0" + $"/drives/{driveID}/items/{folderId}:/{originalFileName}:/createUploadSession";
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + GetAccessToken());
var sessionResponse = client.PostAsync(apiUrl, null).Result.Content.ReadAsStringAsync().Result;
byte[] sContents = System.IO.File.ReadAllBytes(filePath);
var uploadSession = JsonConvert.DeserializeObject<UploadSessionResponse>(sessionResponse);
string response = UploadFileBySession(uploadSession.uploadUrl, sContents);
}
UploadFileBySession is as follows:
private string UploadFileBySession(string url, byte[] file)
{
int fragSize = 1024 * 1024 * 4;
var arrayBatches = ByteArrayIntoBatches(file, fragSize);
int start = 0;
string response = "";
foreach (var byteArray in arrayBatches)
{
int byteArrayLength = byteArray.Length;
var contentRange = " bytes " + start + "-" + (start + (byteArrayLength - 1)) + "/" + file.Length;
using (var client = new HttpClient())
{
var content = new ByteArrayContent(byteArray);
content.Headers.Add("Content-Length", byteArrayLength.ToProperString());
content.Headers.Add("Content-Range", contentRange);
response = client.PutAsync(url, content).Result.Content.ReadAsStringAsync().Result;
}
start = start + byteArrayLength;
}
return response;
}
internal IEnumerable<byte[]> ByteArrayIntoBatches(byte[] bArray, int intBufforLengt)
{
int bArrayLenght = bArray.Length;
byte[] bReturn = null;
int i = 0;
for (; bArrayLenght > (i + 1) * intBufforLengt; i++)
{
bReturn = new byte[intBufforLengt];
Array.Copy(bArray, i * intBufforLengt, bReturn, 0, intBufforLengt);
yield return bReturn;
}
int intBufforLeft = bArrayLenght - i * intBufforLengt;
if (intBufforLeft > 0)
{
bReturn = new byte[intBufforLeft];
Array.Copy(bArray, i * intBufforLengt, bReturn, 0, intBufforLeft);
yield return bReturn;
}
}
UploadSessionResponse class file to deserialize JSON response when you create upload session
public class UploadSessionResponse
{
public string odatacontext { get; set; }
public DateTime expirationDateTime { get; set; }
public string[] nextExpectedRanges { get; set; }
public string uploadUrl { get; set; }
}
For files bigger then 4MB you need to create an uploadSession that you POST to this URL:
https://graph.microsoft.com/v1.0/me/drive/root:/{item-path}:/createUploadSession
Pass an array of items,
{
"item": {
"@odata.type": "microsoft.graph.driveItemUploadableProperties",
"@microsoft.graph.conflictBehavior": "rename",
"name": "largefile.dat"
}
}
I use "@microsoft.graph.conflictBehavior": "overwrite"
, instead of rename
.
The response will provide an upload url to upload the file in batches
{
"uploadUrl": "https://sn3302.up.1drv.com/up/fe6987415ace7X4e1eF866337",
"expirationDateTime": "2015-01-29T09:21:55.523Z"
}
I don't have a c# example but here's a PHP one:
$url = $result['uploadUrl'];
$fragSize = 1024*1024*4;
$file = file_get_contents($source);
$fileSize = strlen($file);
$numFragments = ceil($fileSize / $fragSize);
$bytesRemaining = $fileSize;
$i = 0;
$response = null;
while ($i < $numFragments) {
$chunkSize = $numBytes = $fragSize;
$start = $i * $fragSize;
$end = $i * $fragSize + $chunkSize - 1;
$offset = $i * $fragSize;
if ($bytesRemaining < $chunkSize) {
$chunkSize = $numBytes = $bytesRemaining;
$end = $fileSize - 1;
}
if ($stream = fopen($source, 'r')) {
// get contents using offset
$data = stream_get_contents($stream, $chunkSize, $offset);
fclose($stream);
}
$contentRange = " bytes " . $start . "-" . $end . "/" . $fileSize;
$headers = array(
"Content-Length: $numBytes",
"Content-Range: $contentRange"
);
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$server_output = curl_exec($ch);
$info = curl_getinfo($ch);
curl_close($ch);
$bytesRemaining = $bytesRemaining - $chunkSize;
$i++;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With