我正在使用WCF服务/客户端,试图弄清楚如何用不会阻塞调用者线程的东西替换ManualResetEvent。
最重要的是,await client.CloseAsync()
事件触发之前,不会调用FinishedEventReceived
。
我曾经考虑使用TaskCompletionSource,但是我不确定在这种情况下该如何工作。
我知道代码有点丑陋,完全违背了使用异步编程的目的,我的策略。
有什么想法吗?
private async Task CallServiceMethodAndWaitForEvent()
{
var mre = new ManualResetEvent(true);
var client = new AwesomeClient();
client.FinishedEventReceived += (s, e) =>
{
// Do something with the result, this event is only fired once.
mre.Set();
};
client.UpdateEventReceived += (s, e) =>
{
// This even can fire several times before the finished event.
};
try
{
var parameters = new Parameters()
{
SomeParameter = "Test123",
TestAmount = 10000,
};
var errors = await client.DoWorkAsync(parameters);
Debug.WriteLine(errors);
mre.WaitOne(TimeSpan.FromSeconds(20));
await client.CloseAsync();
}
catch (FaultException ex)
{
}
catch (Exception)
{
client.Abort();
}
}
答案 0 :(得分:2)
可能最简单的方式来完成您想要的操作,就是将ManualResetEvent
替换为-TaskCompletionSource
。例如:
var tcs = new TaskCompletionSource<int>();
var client = new AwesomeClient();
client.FinishedEventReceived += (s, e) =>
{
// Do something with the result, this event is only fired once.
tcs.SetResult(42); // number here is a dummy, since you only want Task
};
...
await tcs.Task;
await client.CloseAsync();
请注意,超时方面比较困难;一种常见的方法是使用Task.Delay
作为后备,而Task.WhenAny
,即
var timeout = Task.Delay(timeoutInterval);
if (timeout == await Task.WhenAny(timeout, tcs.Task))
throw new TimeoutException();
答案 1 :(得分:1)
似乎您正在使用某个实现Event-based Asynchronous Pattern的类。如果您正在执行async
,则真正想要的是使用实现Task-based Asynchronous Pattern的API。
非常感谢Microsoft提供有关adapting EAP to look like TAP的特定指南:
包装基于事件的异步模式(EAP)的实现要比包装APM模式更为复杂,因为与APM模式相比,EAP模式具有更多的变化和更少的结构。为了演示,以下代码包装了
DownloadStringAsync
方法。DownloadStringAsync
接受URI,在下载时引发DownloadProgressChanged
事件以报告进度的多个统计数据,并在完成后引发DownloadStringCompleted
事件。最终结果是一个字符串,其中包含指定URI处的页面内容。public static Task<string> DownloadStringAsync(Uri url) { var tcs = new TaskCompletionSource<string>(); var wc = new WebClient(); wc.DownloadStringCompleted += (s,e) => { if (e.Error != null) tcs.TrySetException(e.Error); else if (e.Cancelled) tcs.TrySetCanceled(); else tcs.TrySetResult(e.Result); }; wc.DownloadStringAsync(url); return tcs.Task; }
希望您可以适应正在使用的特定API。