2013-11-27 159 views
3

我很困惑如何最好地處理這種情況。我不想等待異步調用的響應。具體而言,我有:等待事件處理程序異步

public async Task<IApiData> FetchQueuedApiAsync(TimeSpan receiveTimeout) 
{ 
    var message = await Task.Factory.FromAsync<Message>(
     ReadQueue.BeginReceive(receiveTimeout), ReadQueue.EndReceive); 
    return message.Body as IApiData; 
} 

這個按預期工作。但是,如果超時過期,則不得調用ReadQueue.EndReceive,否則將拋出異常。顯然,FromAsync不知道這一點,並盲目地調用它 - 解除異常。不要求超時調用EndReceive的要求由MSMQ實現,並且超出了我的控制範圍。

當消息準備就緒或發生超時時,隊列公開事件。這是您通常會檢查消息是否存在的地方,然後按照文檔調用EndReceive。標準聽衆....

ReadQueue.ReceiveCompleted += ReadQueue_ReceiveCompleted; 

我的問題是,我不知道如何做到這一點,還是有這個作爲awaitable(即我希望能夠像等待我現在有,但通過處理它代表)。那有意義嗎?

回答

9

通常,當您想要將基於非任務的異步模型轉換爲基於任務的異步模型時,如果還沒有Task方法爲您進行轉換,則可以使用TaskCompletionSource來處理每個案件「手動」:

public Task<IApiData> FetchQueuedApiAsync(TimeSpan receiveTimeout) 
{ 
    var tcs = new TaskCompletionSource<IApiData>(); 

    ReadQueue.BeginReceive(receiveTimeout); 
    ReadQueue.ReceiveCompleted += (sender, args) => 
    { 
     if (timedOut) 
      tcs.TrySetCanceled(); 
     else if (threwException) 
      tcs.TrySetException(exception); 
     else 
      tcs.TrySetResult(ReadQueue.EndReceive() as IApiData); 
    }; 
    return tcs.Task; 
} 

你需要根據你並沒有表現出類型的細節來調整這一點,但這是一般的想法。

+0

我認爲這看起來像我想要的。我不確定事件偵聽器如何在這裏工作。每次調用函數時,是否在ReceiveCompleted中添加了新的處理函數?鑑於這被稱爲很多,我是否需要在某個地方清理它? ReadQueue也在幾個併發線程之間共享。如果多個線程正在偵聽ReceiveCompleted,他們是否都會向他們提供事件? – AndySavage

+0

@AndySavage如果不知道更多關於你正在處理的具體課程,我不能說真的。理想情況下,只有一個方法會在異步事件完成時調用。如果事件是共享的,那麼您需要確定已完成的事件是否與「此」請求相對應。當你完成任務時,你也想刪除處理程序,是的。 – Servy

+0

或者,另一種方法是將一個處理程序永久附加到接收隊列,該接收隊列的任務是確定哪個任務是負責任的,並將其正確設置。 – AnotherParker