Reputation: 21
I am trying to upload file to me mega Account by C# App and I succeeded in upload but without any progress bar and the API has this method "UploadFileAsync" but I can't understand every parameter in this method.
This is from Object browser in VS
IMegaApiClient.UploadFileAsync(string, CG.Web.MegaApiClient.INode, System.IProgress, System.Threading.CancellationToken?)
System.Threading.Tasks.Task<CG.Web.MegaApiClient.INode> UploadFileAsync(string filename, CG.Web.MegaApiClient.INode parent, System.IProgress progress, [System.Threading.CancellationToken? cancellationToken = null]) Member of CG.Web.MegaApiClient.IMegaApiClient
I know filename and INode parent but what should I write in System.IProgress<double> progress
and cancellationToken
?
public uploadFileData uploadToMega(string megaFolderName, string megaFolderID, string filePathOnComputer, string newFileNameOnMega)
{
//Implemnt Struct
uploadFileData myMegaFileData = new uploadFileData();
//Start Mega Cient
var myMegaClient = new MegaApiClient();
//Login To Mega
myMegaClient.Login(Userrrr, Passss);
//Get All (File & Folders) in Mega Account
IEnumerable<INode> nodes = myMegaClient.GetNodes();
//Creat List Of All Folders In Mega Account
List<INode> megaFolders = nodes.Where(n => n.Type == NodeType.Directory).ToList();
//Choose Exist Folder In Mega Account By Name & Id
INode myFolderOnMega = megaFolders.Where(folder => folder.Name == megaFolderName && folder.Id == megaFolderID).FirstOrDefault();
//Upload The File
//Normal Upload
//INode myFile = myMegaClient.UploadFile(filePathOnComputer, myFolderOnMega);
// Upload With progress bar
INode myFile = myMegaClient.UploadFileAsync(filePathOnComputer, myFolderOnMega, progressBar1, default());
//Rename The File In Mega Server
if (string.IsNullOrEmpty(newFileNameOnMega))
{
}
else
{
myMegaClient.Rename(myFile, newFileNameOnMega);
}
//Get Download Link
Uri downloadLink = myMegaClient.GetDownloadLink(myFile);
myMegaFileData.megaFileId = myFile.Id;
Clipboard.SetText(myMegaFileData.megaFileId);
myMegaFileData.megaFileType = myFile.Type.ToString();
myMegaFileData.megaFileName = myFile.Name;
myMegaFileData.megaFileOwner = myFile.Owner;
myMegaFileData.megaFileParentId = myFile.ParentId;
myMegaFileData.megaFileCreationDate = myFile.CreationDate.ToString();
myMegaFileData.megaFileModificationDate = myFile.ModificationDate.ToString();
myMegaFileData.megaFileSize = myFile.Size.ToString();
myMegaFileData.megaFileDownloadLink = downloadLink.ToString();
myMegaClient.Logout();
return myMegaFileData;
}
Upvotes: 0
Views: 3856
Reputation: 6749
System.IProgress
is an interface used so that we can write custom progress types and interchange then with the ones built in. It has one method Report(T)
where T
is an anonymous type.
This means you can write your own progress class but there is one already written in .NET that has that interface and since it qualifies let's use that one. It found in the same namespace as IProgress<T>
and is Progress
and comes with a handy built in ProgressChanged
event we can listen for. So in this first step code example I only introduce the progress. Notice I replaced ProgressBar
with the progress
variable in code.
var progress = new Progress<double>();
progress.ProgressChanged += (s, progressValue) =>
{
//Update the UI (or whatever) with the progressValue
progressBar1.Value = Convert.ToInt32(progressValue);
};
INode myFile = myMegaClient.UploadFileAsync(filePathOnComputer, myFolderOnMega, progress, default());
Now, I won't give you a lesson on Task
but know that Task
can be thought of in a lot of ways like threads but know that a Task
doesn't always have to be a running thread. Anyway, the point is that we use a CancellationToken
to signal canceling of a Task
. Since this UploadFileAsync
is part of a different API we don't need to worry about handling the CancelationToken
but we can supply one to try so that we can try and cancel the upload if we want to. Just note that depending on the API and the Task
canceled can potentially throw an error (usually OperationCanceledException
) or similar. Anyways, if you provided the token then also test canceling it to see how it all plays out.
In this code example I show you how you provide a CancellationToken
. Remember, you can call cancel on this token from another button that might say something like (Stop Upload).
So first, we will make a CancellationTokenSource
and make it at the class
level so that we can use it anywhere within our class.
private CancellationTokenSource uploadCancellationTokenSource = new CancellationTokenSource();
Then before our UploadFileAsync
call we need to make sure it has never been canceled, and if it has we should renew it.
if (uploadCancellationTokenSource.IsCancellationRequested)
{
uploadCancellationTokenSource.Dispose();
uploadCancellationTokenSource = new CancellationTokenSource();
}
INode myFile = myMegaClient.UploadFileAsync(filePathOnComputer, myFolderOnMega, progress, uploadCancellationTokenSource.Token);
And... we can add a button click event or something to cancel the token if we want to.
private void CancelUploadButtonClick(object sender, EventArgs e)
{
if (!uploadCancellationTokenSource.IsCancellationRequested)
uploadCancellationTokenSource.Cancel();
}
Hopefully you understand a little more about what's going on and how to implement it. Here just some mock code of the entire change via your example:
private CancellationTokenSource uploadCancellationTokenSource = new CancellationTokenSource();
public async Task<uploadFileData> uploadToMegaAsync(string megaFolderName, string megaFolderID, string filePathOnComputer, string newFileNameOnMega)
{
//Implemnt Struct
uploadFileData myMegaFileData = new uploadFileData();
//Start Mega Cient
var myMegaClient = new MegaApiClient();
//Login To Mega
myMegaClient.Login(Userrrr, Passss);
//Get All (File & Folders) in Mega Account
IEnumerable<INode> nodes = myMegaClient.GetNodes();
//Creat List Of All Folders In Mega Account
List<INode> megaFolders = nodes.Where(n => n.Type == NodeType.Directory).ToList();
//Choose Exist Folder In Mega Account By Name & Id
INode myFolderOnMega = megaFolders.Where(folder => folder.Name == megaFolderName && folder.Id == megaFolderID).FirstOrDefault();
//Upload The File
//Normal Upload
//INode myFile = myMegaClient.UploadFile(filePathOnComputer, myFolderOnMega);
//NEWLY ADDED
var progress = new Progress<double>();
progress.ProgressChanged += (s, progressValue) =>
{
//Update the UI (or whatever) with the progressValue
progressBar1.Value = Convert.ToInt32(progressValue);
};
//NEWLY ADDED
if (uploadCancellationTokenSource.IsCancellationRequested)
{
uploadCancellationTokenSource.Dispose();
uploadCancellationTokenSource = new CancellationTokenSource();
}
// Upload With progress bar
INode myFile = await myMegaClient.UploadFileAsync(filePathOnComputer, myFolderOnMega, progress, uploadCancellationTokenSource.Token);
//Rename The File In Mega Server
if (string.IsNullOrEmpty(newFileNameOnMega))
{
}
else
{
myMegaClient.Rename(myFile, newFileNameOnMega);
}
//Get Download Link
Uri downloadLink = myMegaClient.GetDownloadLink(myFile);
myMegaFileData.megaFileId = myFile.Id;
Clipboard.SetText(myMegaFileData.megaFileId);
myMegaFileData.megaFileType = myFile.Type.ToString();
myMegaFileData.megaFileName = myFile.Name;
myMegaFileData.megaFileOwner = myFile.Owner;
myMegaFileData.megaFileParentId = myFile.ParentId;
myMegaFileData.megaFileCreationDate = myFile.CreationDate.ToString();
myMegaFileData.megaFileModificationDate = myFile.ModificationDate.ToString();
myMegaFileData.megaFileSize = myFile.Size.ToString();
myMegaFileData.megaFileDownloadLink = downloadLink.ToString();
myMegaClient.Logout();
return myMegaFileData;
}
private void CancelUploadButtonClick(object sender, EventArgs e)
{
if (!uploadCancellationTokenSource.IsCancellationRequested)
uploadCancellationTokenSource.Cancel();
}
I'm going to finish with one more bit of advice. Since we have a class level disposable type (CancelletionTokenSource
) then we should properly implement IDisposable
in your class as well. This is code showing ONLY the implementation of IDisposable
and CancellationTokenSource
and should be used however it fits best into your application.
If you're using your own class... (technically we should mark this sealed or provide and overridable Dispose(bool)
to it but just for the sake of explanation it's like this.
public class Example : IDisposable
{
private CancellationTokenSource uploadCancellationTokenSource = new CancellationTokenSource();
public void Dispose()
{
uploadCancellationTokenSource.Dispose();
GC.SuppressFinalize(this);
}
~Example() => Dispose();
}
If you're in a WinForm or another inherited class that already has IDisposable
implemented.
public class Example2 : Example
{
private CancellationTokenSource uploadCancellationTokenSource = new CancellationTokenSource();
public new void Dispose()
{
uploadCancellationTokenSource.Dispose();
base.Dispose();
}
}
Ok, so finally I updated the uploadToMega
method in the code above to read as a task. This means that the calling method that uses uploadToMega
will now also have to use async
on the method signature and await
on the call.
Note: You can avoid this by keeping things the way they were prior to adding async await
and simply adding .Result
to the end of the UploadFileAsync
method but understand that the thread now holds here until that completes. So if it's the UI thread you will get complications and possibly lose the update to the progress bar. The idea is you want this call to be asynchronous but for the sake of knowing here's the line below with .Result;
added.
INode myFile = myMegaClient.UploadFileAsync(filePathOnComputer, myFolderOnMega, progress, uploadCancellationTokenSource.Token).Result;
If you would like, also update your question with the code that actually calls uploadToMega
and I'll show you how we can update that portion as well. In the end this change will be appreciated.
To better understand what's going on here I advise you to look into the Task
type, understand how it works, and also look into the async await
keywords which allow you to work with Task
in an easier inline fashion.
Feel free to send me the whole project to [email protected] and I'll update it, clean all the compiling errors, and leave some comments for you to help you understand the changes if you need to.
Upvotes: 4