且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

ExecuteAsync RestSharp允许backgroundWorker CancellationPending C#

更新时间:2022-11-27 12:10:18

这里有两个潜在的问题.

There are a couple of potential problems here.

首先,您似乎正在尝试从后台线程访问UI元素(以及打开MessageBox).这有可能引发CrossThread异常*.

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 });
            }
        );
    }
}

将后台工作人员的RunWorkerCompleted方法与此相关联,并在此处执行所有后处理:

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"
}

此外,如果您使用的是4.0+,则建议您查看任务并行库.它可以使您的代码更简洁IMO :).

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

最后,请注意上面的代码,将会发生的情况是,后台工作人员很有可能在所有Rest调用完成之前就返回已完成.这可能会相当快地运行,并且由于无法以这种方式取消(后台工作人员已经完成)而使调用仍然继续进行(但我相信对于每个Rest调用都可以执行此操作).因此,在我看来,真正的问题是取消检查在代码的错误部分(注意,我将其移入了循环,以便可以在处理每个文件之后进行检查).您已经在后台线程中运行,所以在我看来,调用另一个异步是没有意义的(除非您的意图是卸载要发送的数据的循环,然后再卸载实际的发送).

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.

*可能不行,因为您仅访问而不是更新UI元素,并且您确实说过这部分正在工作(尽管它可能适用于MessageBox)

*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)