/// <inheritdoc /> public Task <FtpResponse> Execute(IFtpCommandBase handler, FtpCommand command) { lock (_syncRoot) { if (_handlerTask != null) { return(null); } _cancellationTokenSource = new CancellationTokenSource(); _handlerTask = handler.Process(command, _cancellationTokenSource.Token); } var taskCanceled = _handlerTask .ContinueWith( t => { var response = new FtpResponse(426, "Connection closed; transfer aborted."); Debug.WriteLine($"Background task cancelled with response {response}"); return(response); }, TaskContinuationOptions.OnlyOnCanceled); var taskCompleted = _handlerTask .ContinueWith( t => { var response = t.Result; Debug.WriteLine($"{DateTimeOffset.UtcNow} Background task finished successfully with response {response}"); return(response); }, TaskContinuationOptions.OnlyOnRanToCompletion); var taskFaulted = _handlerTask .ContinueWith( t => { var ex = t.Exception; _connection.Log?.LogError(ex, "Error while processing background command {0}", command); var response = new FtpResponse(501, "Syntax error in parameters or arguments."); Debug.WriteLine($"Background task failed with response {response}"); return(response); }, TaskContinuationOptions.OnlyOnFaulted); taskFaulted.ContinueWith(t => { }, TaskContinuationOptions.OnlyOnCanceled); taskCompleted.ContinueWith(t => { }, TaskContinuationOptions.OnlyOnCanceled); taskCanceled.ContinueWith(t => { }, TaskContinuationOptions.OnlyOnCanceled); return(Task.Run( () => { var tasks = new List <Task <FtpResponse> > { taskCompleted, taskCanceled, taskFaulted }; do { try { var waitTasks = tasks.Where(x => !x.IsCompleted).Cast <Task>().ToArray(); if (waitTasks.Length != 0) { Debug.WriteLine($"Waiting for {waitTasks.Length} background tasks"); Task.WaitAll(waitTasks); } } catch (AggregateException ex) { ex.Handle(e => e is TaskCanceledException); } }while (tasks.Any(t => !t.IsCompleted)); var response = tasks.Single(x => x.Status == TaskStatus.RanToCompletion).Result; Debug.WriteLine($"{DateTimeOffset.UtcNow} Background task finished with response {response}"); lock (_syncRoot) { _handlerTask = null; } return response; })); }