ExecuteAsync RestSharp允许backgroundWorker取消挂起c#

ExecuteAsync RestSharp允许backgroundWorker取消挂起c#,c#,backgroundworker,blocking,kill,restsharp,C#,Backgroundworker,Blocking,Kill,Restsharp,我不熟悉C#、RestSharp和线程,所以下面是我要做的: 我已经做了一个程序,允许我上传照片到tumblr,我已经上传工作到目前为止。现在我需要停止按钮来工作,我相信这意味着我必须使用ExecuteAsync()而不是Execute()。 我还将我的代码放在backgroundworker中,如下所示: private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { if (backgroundWor

我不熟悉C#、RestSharp和线程,所以下面是我要做的:
我已经做了一个程序,允许我上传照片到tumblr,我已经上传工作到目前为止。现在我需要停止按钮来工作,我相信这意味着我必须使用
ExecuteAsync()
而不是
Execute()
。 我还将我的代码放在backgroundworker中,如下所示:

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 });
    }
    }
}
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 });
            }
        );
    }
}
我相信我的设置是正确的。当我按
upload
时,它会相应地转到
else
。然而,我认为
restreponse response=restClient.Execute(request)这是阻塞,不允许我的代码继续检查标志。


这就是我试图取消它的方式

public void stopButton_Click(object sender, EventArgs e)
{
    doneBox.Items.Add("You pressed the stop button.");
    backgroundWorker1.WorkerSupportsCancellation = true;
    backgroundWorker1.CancelAsync();
}
此外,如果这是相关的,我有:

public委托void UpdateTextCallback(字符串项)
允许我调用
UpdateText
FinishedText
,如上文
backgroundWorker1\u-DoWork
所示



对于我的问题,在这种情况下如何使用
ExecuteAsync
?我已经搜索过了,但是我找不到任何对我有帮助的东西,我找不到一个与我的代码类似的示例,而且由于我是c#新手,我无法将它转换为我想要的。

而且,我也乐于接受建议,如果您看到我的代码中存在一些低效或其他问题,我将很乐意接受您的建议。


谢谢。

这里有几个潜在的问题

首先,您似乎试图从后台线程访问UI元素(以及打开MessageBox)。这有可能引发交叉线程异常*

其次,您的代码应该更像这样:

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 });
    }
    }
}
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
方法连接到此方法,并在此处执行所有后期处理:

private void backgroundWorker1_RunWorkerCompleted(object sender,
    RunWorkerCompletedEventArgs e)
{
    if(e.Cancelled)
        MessageBox.Show("You pressed Cancel"
}
另外,如果您使用的是4.0+,那么我建议您查看。它可以使您的代码更干净(IMO:)

最后,关于上述代码的一个注意事项是,后台工作程序很有可能在所有剩余调用完成之前返回completed。这可能会运行得相当快,并且让调用继续,因为它们不能以这种方式取消(后台工作人员将已经完成)(但我相信对于每个Rest调用都有一种方法可以做到这一点)。因此,在我看来,真正的问题在于取消检查位于代码的错误部分(注意,我将其移动到循环中,以便在处理每个文件后可以对其进行检查)。您已经在后台线程中运行,因此在我看来,调用另一个异步是没有意义的(除非您的目的是卸载要发送的数据的循环,然后卸载实际的发送)

因此,总结而言。我提供了调用异步的方法,但我相信更大的问题是您没有正确地检查cancel调用


*可能不是这样,因为您只是在访问UI元素,而不是在更新UI元素,而且您确实说过此部分正在工作(不过对于MessageBox可能会工作)

谢谢,当我尝试使用此代码时,我得到
一个名为response的局部变量不能在此作用域中声明,因为它将赋予“response”不同的含义,而“response”已在“parent”或curren't作用域中用于表示其他内容。
如果我将其更改为“restreponse”\u response=restClient.ExecuteAsync(request,`it删除此错误,但现在我得到
无法隐式地将类型RestSharp.RestRequestAsyncHandle'转换为'RestSharp.RestResponse'
@antera我已更新了我的答案,以删除存储异步调用响应的操作(因为这里确实不需要它)。此外,我还建议使用RunWorkerCompleted更好地处理潜在的UI处理错误。最后,您可以将客户端的超时设置为更高的值(我不确定默认值)修复您当前的超时问题。但是,这似乎解决了您最初的问题。如果这是真的,我们将永远感谢您的支持和接受的答案:)谢谢,我感谢您的帮助。我搜索了源代码并通过以下操作使其正常工作:
byte[]byteArray=File.ReadAllBytes(FolderName+“\\”+项);
request.AddFile(“data”,byteArray,FolderName+“\\\”+项);
老实说,我不知道为什么会修复它,但它确实修复了:D.@antera Hrmm,只是看了看代码,它看起来应该可以工作……进一步看:)我猜它可能与StreamReader有关?真有趣。但是,您的工作代码以不同的方式获取数据…这可以解释为什么一个工作,另一个不工作。您在工作开始时看到取消的几率为零。将测试移到循环内。可能已经足够好了。