I have code for uploading files that work on UWP. I've looked for a way to cancel the upload. Didn't find. There is a way to cancel that? I tried to add CancellationToken
but there is no place to set this in the DriveAPI
properties.
try
{
StorageFile file = StorageFile.GetFileFromPathAsync(path).AsTask().Result;
String ID;
var fileMetadata = new Google.Apis.Drive.v3.Data.File()
{
Name = Path.GetFileName(file.Path),
MimeType = "application/octet-stream"
};
using (var stream = file.OpenStreamForReadAsync().Result)
{
var request = this.drive.Files.Create(fileMetadata, stream, "application/octet-stream");
request.ProgressChanged += (IUploadProgress progressInfo) =>
{
if (progressInfo.Status == UploadStatus.Completed)
{
Debug.WriteLine($"done!");
prog.Report(progressInfo);
}
else if (progressInfo.Status == UploadStatus.Failed)
{
Debug.WriteLine($"Failed To Upload Into Google Drive");
prog.Report(progressInfo);
}
else
{
Debug.WriteLine(Convert.ToDouble(progressInfo.BytesSent/(1024*1024)) + " MB has sent");
prog.Report(progressInfo);
}
};
request.ChunkSize = 262144;
request.Upload();
var uploadedFile = request.ResponseBody;
Debug.WriteLine($"File uploaded: {uploadedFile.Name} ({uploadedFile.Id})");
ID = uploadedFile.Id;
return ID;
}
}
I tried to place if(cancelationtoken)
in progressInfo.Status == UploadStatus.Uploading
but It didn't stop the uploading. it only stops retorting to Progress.
Someone knows maybe how to dispose of the entire Task<>
?
That's what I tried to do:
request.ProgressChanged += (IUploadProgress progressInfo) =>
{
if (progressInfo.Status == UploadStatus.Completed)
{
Debug.WriteLine($"done!");
prog.Report(progressInfo);
}
else if (progressInfo.Status == UploadStatus.Failed)
{
Debug.WriteLine($"Failed To Upload Into Google Drive");
prog.Report(progressInfo);
}
else if (progressInfo.Status == UploadStatus.Uploading)
{
//(if(canceltoken.iscancel)...){}
Debug.WriteLine(Convert.ToDouble(progressInfo.BytesSent/(1024*1024)) + " MB has sent");
prog.Report(progressInfo);
}
};
You wish to be able to cancel a file upload and this could be made easier by making your upload method async
. Then you would be able to make proper use of the await operator and could put the cancellation token in the upload call in this format:
await request.UploadAsync(cancellationToken)
I notice a couple of places in your code where you downgrade async
methods to blocking calls e.g.
StorageFile.GetFileFromPathAsync(path).AsTask().Result
or
var stream = file.OpenStreamForReadAsync().Result
This somewhat defeats the purpose of those methods being asynchronous in the first place, and you may run into some deadlocks or other threading problems doing this.
So I would say it could be highly advantageous to reframe your method something like this:
using Metadata = Google.Apis.Drive.v3.Data.File;
async Task<string> Upload(string path, CancellationToken cancellationToken, IProgress<IUploadProgress> prog)
{
StorageFile file = await StorageFile.GetFileFromPathAsync(path);
string ID;
var fileMetadata = new Metadata()
{
Name = Path.GetFileName(file.Path),
MimeType = "application/octet-stream"
};
using (var stream = await file.OpenStreamForReadAsync())
{
var request = this.drive.Files.Create(fileMetadata, stream, "application/octet-stream");
request.ProgressChanged += (IUploadProgress progressInfo) =>
{
if (progressInfo.Status == UploadStatus.Completed)
{
Debug.WriteLine($"done!");
prog.Report(progressInfo);
}
else if (progressInfo.Status == UploadStatus.Failed)
{
Debug.WriteLine($"Failed To Upload Into Google Drive");
prog.Report(progressInfo);
}
else
{
Debug.WriteLine(Convert.ToDouble(progressInfo.BytesSent / (1024 * 1024)) + " MB has sent");
prog.Report(progressInfo);
}
};
request.ChunkSize = 262144;
await request.UploadAsync(cancellationToken);
var uploadedFile = request.ResponseBody;
Debug.WriteLine($"File uploaded: {uploadedFile.Name} ({uploadedFile.Id})");
ID = uploadedFile.Id;
return ID;
}
}
Calling your async method
You don't necessarily have to wait for your async method to run. Here's an example of discarding the return value in a "fire and forget" call to the Upload
method in a button click handler. You can also cancel a long-running upload with the second button handler.
CancellationTokenSource? _cts;
Progress Progress { get; } = new Progress();
void ButtonUpload_Click(object sender, EventArgs e)
{
var path = Path.Combine(SpecialPath.GoogleOutbound.GetRelEnvPath(), "myUploadFile.txt");
_cts = new CancellationTokenSource();
_ = Upload(path, _cts.Token, Progress);
}
void ButtonCancelUpload_Click(object sender, EventArgs e)
{
_cts?.Cancel();
}