Code provided above contains error
if (read > 0)
fileStream.Write(bytesInStream, 0, bytesInStream.Length);
Which is incorrect and should be:
if (read > 0)
fileStream.Write(bytesInStream, 0, read);
and is a bit clumsy with
int lastChunkSize = Convert.ToInt32(size % DefaultChunkSize) - numberOfChunks - 1;
I refactored it a bit and decided to publish it here.
Correct code
private int DefaultChunkSize = 5 * 1024 * 1024;//5MB
private int BufferSize = 4096;
...
int chunkSize = DefaultChunkSize;
long offset = 0; // cursor location for updating the Range header.
byte[] buffer = new byte[BufferSize];
var driveItemInfo = await _api.Drive.Root.ItemWithPath(path).Request().GetAsync();
object downloadUrl;
driveItemInfo.AdditionalData.TryGetValue("@microsoft.graph.downloadUrl", out downloadUrl);
long size = (long) driveItemInfo.Size;
int numberOfChunks = Convert.ToInt32(size / DefaultChunkSize);
// We are incrementing the offset cursor after writing the response stream to a file after each chunk.
int lastChunkSize = Convert.ToInt32(size % DefaultChunkSize);
if (lastChunkSize > 0) {
numberOfChunks++;
}
for (int i = 0; i < numberOfChunks; i++) {
// Setup the last chunk to request. This will be called at the end of this loop. if (i == numberOfChunks - 1)
{
chunkSize = lastChunkSize;
}
//Create the request message with the download URL and Range header.
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, (string) downloadUrl);
//-1 because range is zero based
request.Headers.Range = new System.Net.Http.Headers.RangeHeaderValue(offset, chunkSize + offset - 1);
// We can use the the client library to send this although it does add an authentication cost.
// HttpResponseMessage response = await graphClient.HttpProvider.SendAsync(req);
// Since the download URL is preauthenticated, and we aren't deserializing objects,
// we'd be better to make the request with HttpClient.
var client = new HttpClient();
HttpResponseMessage response = await client.SendAsync(request);
int totalRead = 0;
using(Stream responseStream = await response.Content.ReadAsStreamAsync()) {
int read;
while ((read = await responseStream.ReadAsync(buffer: buffer, offset: 0, count: buffer.Length)) > 0) {
stream.Write(buffer, 0, read);
totalRead += read;
}
}
offset += totalRead; // Move the offset cursor to the next chunk.
}