ExecuteAsync RestSharp to allow backgroundWorker CancellationPending c#

本秂侑毒 提交于 2019-12-13 16:38:07

问题


I'm new to C#, RestSharp, and threading, so heres what I'm trying to do:
I have made a program that will allow me to upload photos to tumblr, and I have the uploading working so far. Now I need the stop button to work, which I believe means I must use ExecuteAsync() instead of Execute(). I also have my code put in a backgroundworker, like this:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    if (backgroundWorker1.CancellationPending)
    {
        e.Cancel = true;
        MessageBox.Show("You pressed Cancel.");
    }
    else
    {
    var restClient = new RestClient("http://tumblr.com/api/write");
    foreach (string item in queueBox.Items)
    {
        var request = new RestRequest(Method.POST);
        request.RequestFormat = DataFormat.Json; //I don't know if this line is necessary
        request.AddParameter("email", usernameBox.Text);
        request.AddParameter("password", passwordBox.Text);
        request.AddParameter("type", "photo");
        request.AddFile("data", FolderName + "\\" + item);
        RestResponse response = restClient.Execute(request);
        doneBox.Invoke(new UpdateTextCallback(this.UpdateText),
            new object[] { item });
    }
    }
}

I believe I have set this up correctly. When I press upload it goes to else accordingly. However, I think that RestResponse response = restClient.Execute(request); this is blocking, which isn't allowing my code to continue checking the flag.

This is how I attempt to cancel it.

public void stopButton_Click(object sender, EventArgs e)
{
    doneBox.Items.Add("You pressed the stop button.");
    backgroundWorker1.WorkerSupportsCancellation = true;
    backgroundWorker1.CancelAsync();
}

Also, incase this is relevant, I have:

public delegate void UpdateTextCallback(string item); which allows me to call UpdateText and FinishedText as seen above in backgroundWorker1_DoWork.



For my question, how can I use ExecuteAsync in this context? I have searched but I cannot find anything that will help me, I can't find an example that is similar to my code, and since I'm new to c# I am unable to convert it to what I want.

And also, I am open to suggestions, if you see some inefficiency in my code or what not, I will be happy to accept your suggestions.

Thank you.


回答1:


There are a couple of potential problems here.

First, you seem to be trying to access a UI element from your background thread (as well open a MessageBox). This has a potential of throwing a CrossThread exception*.

Second, your code should look more like this:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    var restClient = new RestClient("http://tumblr.com/api/write");
    foreach (string item in queueBox.Items)
    { 
        //This should be inside the foreach 
        //as it is your loop that will check for cancel. 
        //Your code is procedural once it is in the backgroundworker
        //so it would never return to the spot you had it
        if (backgroundWorker1.CancellationPending)
        {
            e.Cancel = true;
            //MessageBox.Show("You pressed Cancel.");
            //Removed this to the background worker completed method below
            //This avoids any UI cross thread exceptions
            return;
        }
        var request = new RestRequest(Method.POST);
        //I believe Json is default for Restsharp, but you would have to play with it
        request.RequestFormat = DataFormat.Json; //I don't know if this line is necessary
        request.AddParameter("email", usernameBox.Text);
        request.AddParameter("password", passwordBox.Text);
        request.AddParameter("type", "photo");
        request.AddFile("data", FolderName + "\\" + item);
        //If you just pass in item to the below Func, it will be a closure
        //Meaning, any updates in the loop will propogate into the Action
        var newItemToAvoidClosure = item;
        //To use Async, you set up the callback method via a delegate
        //An anonymous method is as good as any here
        restClient.ExecuteAsync(request, 
            response=>
            { 
                //Maybe you should do something with the response?
                //Check the status code maybe?
                doneBox.Invoke(new UpdateTextCallback(this.UpdateText),
                    new object[] { newItemToAvoidClosure });
            }
        );
    }
}

Wire your background worker's RunWorkerCompleted method to this and perform all of your post processing here:

private void backgroundWorker1_RunWorkerCompleted(object sender,
    RunWorkerCompletedEventArgs e)
{
    if(e.Cancelled)
        MessageBox.Show("You pressed Cancel"
}

Also, if you are using 4.0+, then I suggest looking into the Task Parallel Library. It can make your code much cleaner IMO :).

Finally, a note about the above code, what will happen is that the background worker has a high potential to return completed before all of the Rest calls complete. This will probably run fairly quick, and leave the calls still to continue as they are not cancellable in this fashion (the background worker will have already completed)(but I believe there is a way to do this for each Rest call). So, it seems to me that the real problem was that the cancellation check was in the wrong part of the code (notice I moved it inside the loop, so that it can be checked after each file was processed). You are already running in a background thread, so it seems to me that there is no point to calling another async (unless your intent is to offload the looping of the data to be sent, which then offloads the actual sending).

So, in conclusion. I provided the way to call the async, but I believe the bigger problem was that you were not checking for the cancel call appropriately.

*It may not since you are only accessing and not updating the UI element, and you did say this part was working (it probably will for the MessageBox, though)



来源:https://stackoverflow.com/questions/9833813/executeasync-restsharp-to-allow-backgroundworker-cancellationpending-c-sharp

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!