等待事件处理程序的异步

And*_*age 3 c# asynchronous msmq

我很困惑如何最好地处理这种情况.我不想等待异步调用的响应.具体来说,我有:

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

这按预期工作.但是,如果超时到期,则不得调用ReadQueue.EndReceive,否则将引发异常.显然,FromAsync并不知道这一点并盲目地调用它 - 解雇异常.不要在超时时调用EndReceive的要求由MSMQ实现,超出了我的控制范围.

当消息准备就绪或发生超时时,队列会公开事件.这是您通常检查消息是否存在的地方,然后根据文档调用EndReceive.标准听众......

ReadQueue.ReceiveCompleted += ReadQueue_ReceiveCompleted;
Run Code Online (Sandbox Code Playgroud)

我的问题是,我不明白如何做到这一点,仍然有这样的等待(即我希望能够等待我现在,但通过委托处理它).那有意义吗?

Ser*_*rvy 9

通常,当您想要将一些基于任务的异步模型转换为基于任务的异步模型时,如果还没有一种Task方法可以为您进行转换,则使用a 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;
}
Run Code Online (Sandbox Code Playgroud)

您需要根据未显示的类型的具体情况进行调整,但这是一般性的想法.