2015-05-26 69 views
4

我有这条线,它不阻塞(同步)Web服务调用,并正常工作:如何取消RestSharp同步execute()调用?

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

(该var代表IRestResponse<DataRequestResponse>

但是,现在我希望能够取消它(来自另一个线程)。 (我发现这个similar question,但我的代码必须保持同步 - 代码修改在这个函数保持本地化。)

我发现CancellationTokenSourceExecuteTaskAsync(),这需要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函数,但作为一个同步功能(即不会返回,直到请求完成),这对我来说没有多大用处!

回答

0

鉴于此同步调用:

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

(对不起,不能等待赏金见效,所以不得不工作,这一点我自己,通过试错这个下午...)

3

您的通话

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; 
+0

感谢您的回答。上面的代码是否需要在用'async'标记的函数中?这是我尝试使用ExecuteTaskAsync函数时遇到的问题之一。 –

+0

@DarrenCook虽然通常是一个好主意,可以将'async'从您的调用堆栈中调出,您不必这样做。在上面的示例中,您会注意到没有'await'语句,而是使用'response = task.Result;'阻塞等待。所以包含这个代码的方法不应该被标记为'async'。或者,你可以使它'异步任务 MyMethod(...){...返回等待任务; }'并且让调用'MyMethod'的客户端代码进行等待(阻塞或使用'await')。 – Alex