简体   繁体   中英

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 (ie I want to be able to await like I have now, but handle it via the delegate). Does that make sense?

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM