IEnumerator <Task <AsyncCompletedEventArgs> > FetchOperationAsyncHelper(object state, CancellationToken token, int timeout, Action continuator) { var tcs = new TaskCompletionSource <AsyncCompletedEventArgs>(); // prepare the timeout CancellationToken newToken; if (timeout != Timeout.Infinite) { var cts = CancellationTokenSource.CreateLinkedTokenSource(token); TaskExt.CancelAfterEx(cts, timeout * 1000); newToken = cts.Token; } else { newToken = token; } /* handle completion */ AsyncCompletedEventHandler handler = (sender, args) => { if (args.Cancelled) { tcs.TrySetCanceled(); } else if (args.Error != null) { tcs.SetException(args.Error); } else { tcs.SetResult(args); } }; this.FetchOperationCompleted += handler; try { using (newToken.Register(() => { try { tcs.SetCanceled(); } catch (InvalidOperationException) { /* cancel when already finished, does not matter */ #if DEBUG Tracing.WarningDAL("Canceled async db operation, when it has already completed."); #endif } }, useSynchronizationContext: false)) { this.StartFetchOperation(state); yield return(tcs.Task.Continuation(continuator)); } } finally { this.FetchOperationCompleted -= handler; } }