Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Await async with event handler

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?

like image 785
AndySavage Avatar asked Dec 02 '25 05:12

AndySavage


1 Answers

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.

like image 130
Servy Avatar answered Dec 03 '25 17:12

Servy



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!