Eng.Mohamed Bassuny
Eng.Mohamed Bassuny

Reputation: 21

How can I make UploadFileAsync in Mega API

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

Answers (1)

Michael Puckett II
Michael Puckett II

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

Related Questions