如何取消RestSharp的同步execute()调用

本文关键字:同步 execute 调用 RestSharp 取消 何取消 | 更新日期: 2023-09-27 17:50:43

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

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

(var代表IRestResponse<DataRequestResponse>)

但是,现在我希望能够取消它(从另一个线程)。(我发现了类似的问题,但我的代码必须保持同步-代码更改必须在此函数中保持本地化。)

我找到了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函数,但作为一个同步函数(即,直到请求完成才返回),这对我没有多大用处!

如何取消RestSharp的同步execute()调用

调用的异步对应

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

public virtual Task<IRestResponse<T>> ExecuteTaskAsync<T>(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; 

给定这个同步调用:

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

(对不起,不能等待赏金结出果实,所以不得不为自己解决这个问题,通过试验和错误今天下午…)