【问题标题】:How to cancel a RestSharp synchronous execute() call?如何取消 RestSharp 同步 execute() 调用?
【发布时间】:2015-05-26 09:25:01
【问题描述】:

我有这条线,它执行阻塞(同步)网络服务调用,并且工作正常:

var response = client.Execute<DataRequestResponse>(request);

var代表IRestResponse&lt;DataRequestResponse&gt;

但是,现在我希望能够取消它(从另一个线程)。 (我找到了这个similar question,但我的代码必须保持同步——代码更改必须在这个函数中保持本地化。)

我找到了CancellationTokenSource,还有一个ExecuteTaskAsync(),它需要一个CancellationToken。 (请参阅https://stackoverflow.com/a/21779724/841830)听起来它可以完成这项工作。我得到了这段代码:

var cancellationTokenSource = new CancellationTokenSource();
var task = client.ExecuteTaskAsync(request, cancellationTokenSource.Token);
task.Wait();
var response = task.Result;

最后一行拒绝编译,告诉我它不能进行隐式转换。所以我尝试了一个明确的演员:

IRestResponse<DataRequestResponse> response = task.Result as IRestResponse<DataRequestResponse>;

编译、运行,但随后崩溃(抛出 NullReferenceException,说“对象引用未设置为对象的实例”)。

(顺便说一句,一旦我有这个工作,那么cancellationTokenSource.Token当然会从主线程传入,我还将添加一些代码来检测何时发生中止:我会抛出一个异常.)

我的备用计划只是中止正在运行的整个线程。粗略,但目前这实际上已经足够了。但如果可以的话,我宁愿“正确地”做。

更多信息:

同步 Execute 调用在此处:https://github.com/restsharp/RestSharp/blob/master/RestSharp/RestClient.Sync.cs#L55 最终调用 Http.AsGet()Http.AsPost(),然后在此处结束:https://github.com/restsharp/RestSharp/blob/master/RestSharp/Http.Sync.cs#L194

换句话说,RestSharp 在幕后使用的是HttpWebRequest.GetResponse。它有一个Abort 函数,但作为一个同步函数(即在请求完成之前不会返回)对我来说用处不大!

【问题讨论】:

    标签: c# multithreading mono restsharp


    【解决方案1】:

    您调用的异步对应项

    var response = client.Execute<DataRequestResponse>(request);
    

    public virtual Task&lt;IRestResponse&lt;T&gt;&gt; ExecuteTaskAsync&lt;T&gt;(IRestRequest request, CancellationToken token)RestSharp 异步方法。

    它需要一个取消令牌,并返回一个具有正确返回类型签名的任务。要使用它并等待其(可取消)完成,您可以将示例代码更改为:

    var cancellationTokenSource = new CancellationTokenSource();
    
    // ...
    
    var task = client.ExecuteTaskAsync<DataRequestResponse>(
        request,    
        cancellationTokenSource.Token);
    
    // this will wait for completion and throw on cancellation.
    var response = task.Result; 
    

    【讨论】:

    • 感谢您的回答。上面的代码是否需要在带有async 标记的函数中?这是我在尝试使用 ExecuteTaskAsync 函数时遇到的问题之一。
    • @DarrenCook 虽然在调用堆栈中一直冒泡async 通常是个好主意,但您不必这样做。在上面的示例中,您会注意到没有await 语句,而是使用response = task.Result; 的阻塞等待。所以包含此代码的方法不应标记为async。或者,您可以将其设为async Task&lt;DataRequestResponse&gt; MyMethod(...) { ... return await task; },并让调用MyMethod 的客户端代码进行等待(阻塞或使用await)。
    【解决方案2】:

    鉴于此同步调用:

    var response = client.Execute<MyData>(request);
    process(response);
    

    改成:

    var response = null;
    EventWaitHandle handle = new AutoResetEvent (false);
    client.ExecuteAsync<MyData>(request, r => {
        response = r;
        handle.Set();
        });
    handle.WaitOne();
    process(response);
    

    相当于同步版,没有任何好处。这是添加中止功能的一种方法:

    bool volatile cancelAllRequests = false;
    ...
    var response = null;
    EventWaitHandle handle = new AutoResetEvent (false);
    RestRequestAsyncHandle asyncRequest = client.ExecuteAsync<MyData>(request, r => {
         response = r;
         handle.Set();
         });
     while(true){            
         if(handle.WaitOne(250))break;   //Returns true if async operation finished
         if(cancelAllRequests){
             asyncRequest.WebRequest.Abort();
             return;
             }
         }
    process(response);
    

    (抱歉,等不及赏金结果了,所以今天下午必须自己解决这个问题,通过反复试验......)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-10-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-14
      相关资源
      最近更新 更多