2015-05-26 64 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