private Task SimplifiedTransferRequest(TransferMethod method, string fileName, string directory, string channelPassword, bool overwrite, bool resume, CancellationToken cancellationToken) { TaskCompletionSource <Error> taskCompletionSource = new TaskCompletionSource <Error>(); // check if task is already canceled. if (cancellationToken.IsCancellationRequested) { // if yes, exit early. taskCompletionSource.SetCanceled(); return(taskCompletionSource.Task); } // the return code can show up in FileTransferStatusReceived, and ServerError. // and both can signal the end of the operation. // that is why ServerError is mapped on to the handler for FileTransferStatusReceived // this way, the clean up code has to be written once. // CancellationToken does not directly signal the abort, but instead calls TryHaltTransfer. // which will result in a FileTransferStatusReceived. FileTransfer self = null; Task startTask; string returnCode = Connection.GetNextReturnCode(out startTask); // = null, to make the c# compiler happy. FileTransferStatusEventHandler eventHandler = null; eventHandler = (transfer, status) => { if (transfer != self) { return; } // any event for transfer signals the end of the operation Connection.FileTransferStatusReceived -= eventHandler; // translate the error code into task state switch (status) { case Error.FileTransferComplete: taskCompletionSource.SetResult(Error.Ok); break; case Error.FileTransferCanceled: taskCompletionSource.SetCanceled(); break; default: taskCompletionSource.SetException(Library.CreateException(status)); break; } }; startTask.ContinueWith(antecendent => { // failed to initiate a transfer Connection.FileTransferStatusReceived -= eventHandler; // pass exception to user taskCompletionSource.SetException(antecendent.Exception); }, cancellationToken, TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Current); Connection.FileTransferStatusReceived += eventHandler; self = method(this, channelPassword, fileName, overwrite, resume, directory, returnCode); if (cancellationToken != CancellationToken.None) { // register cancellationToken cancellationToken.Register(() => Library.Api.TryHaltTransfer(self, true, null)); } return(taskCompletionSource.Task); }