I'm working on a WCF service/client trying to figure out how to replace a ManualResetEvent with something that won't block the caller thread.
Most important is that await client.CloseAsync()
won't be called until the FinishedEventReceived
event has been fired.
I've looked at using a TaskCompletionSource but I'm somewhat unsure how that would work in this case.
I know the code is a bit ugly and totally defeats the purpose of using asynchrounously programming, my apoligies.
Any ideas?
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();
}
}
Probably the simplest way to do what you want would be to replace the ManualResetEvent
with - as you mentioned - a TaskCompletionSource
. For example:
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();
Note that the timeout aspect is harder; a common approach there is to use Task.Delay
as a fallback, and Task.WhenAny
, i.e.
var timeout = Task.Delay(timeoutInterval);
if (timeout == await Task.WhenAny(timeout, tcs.Task))
throw new TimeoutException();