Await async with event handler

asynchronous, c#, msmq

Solution

As a rule when you want to convert some non-task based asynchronous model to a task based asynchronous model, if there isn't already a `Task` method to do the conversion for you, you use a `TaskCompletionSource` to handle each of the cases "manually":

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

You'll need to adjust this based on the specifics of the types you didn't show, but this is the general idea.

Problem

I am confused as to how best handle this situation. I wan't to await the response of an asynchronous call. Specifically I have: ``` public async Task<IApiData> FetchQueuedApiAsync(TimeSpan receiveTimeout) { var message = await Task.Factory.FromAsync<Message>( ReadQueue.BeginReceive(receiveTimeout), ReadQueue.EndReceive); return message.Body as IApiData; } ``` This works as expected. However, if the timeout expires then ReadQueue.EndReceive must not be called else it will throw an exception. Obviously FromAsync doesn't know this and calls it blindly - firing the exception. The requirement not to call EndReceive on timeouts is implemented by MSMQ and beyond my control. The queue exposes an event when a message is ready or a timeout occurs. This is where you would normally check if a message was present, and THEN call EndReceive as per the documentation. Standard listener.... ``` ReadQueue.ReceiveCompleted += ReadQueue_ReceiveCompleted; ``` My question is that I don't understand how to do that and still have this as awaitable (i.e. I want to be able to await like I have now, but handle it via the delegate). Does that make sense?

Original source