Any plans to make it more async/await friendly?

Dec 8, 2013 at 8:58 AM
It would be nice if we can use the new async/await feature in C# 5.0 with System.Net.FtpClient.
Coordinator
Dec 9, 2013 at 5:45 PM
I honestly haven't dug into the asyc/await pattern so I'm not familiar with how to implement it. I know syntactically it would be a lot prettier with newer versions of the language, just haven't had time to do it so it's not high on my priority list. Right now I'm pretty much just supporting what's already there, not adding anything new. In the future I might find the time but right now I don't have it to invest.
Jun 5, 2014 at 4:49 PM
deer, the current "async" code wraps the sync API in thread pool calls. You would be better off just using the sync calls directly right now.
Coordinator
Jun 5, 2014 at 4:59 PM
CoryIdComLog, is there a specific problem you want to point out with the way the IAsyncResult programming pattern is implemented in this project?
Jan 23, 2015 at 6:48 PM
Edited Jan 23, 2015 at 6:49 PM
You can convert easily between Async Callback and IAsyncResult programming patterns using Task<>.Factory.FromAsync

For example:
            FtpClient client = ...
            Stream s = await Task<Stream>.Factory
                .FromAsync(Client.BeginOpenRead, Client.EndOpenRead, path, Client);
You can also make it handle cancellation:
            FtpClient client = ...
            Stream s = await Task<Stream>.Factory
                .FromAsync(Client.BeginOpenRead, Client.EndOpenRead, path, Client)
                .HandleCancellation(Token);
HandleCancellation is a helper method that I got from StackOverflow.

It goes like this:
namespace MyNamespace
{
    /// <summary>
    /// Task.Factory.FromAsync does not come with cancellationtokensource built in.  
    /// This extension method allows us to handle that kind of behavior anyways.
    /// 
    /// This code came from:
    /// <see href="https://stackoverflow.com/questions/24980427/task-factory-fromasync-with-cancellationtokensource"/>.
    /// </summary>
    public static class TaskExtensions
    {
        public async static Task<TResult> HandleCancellation<TResult>(
            this Task<TResult> asyncTask,
            CancellationToken cancellationToken)
        {
            // Create another task that completes as soon as cancellation is requested.
            // http://stackoverflow.com/a/18672893/1149773
            var tcs = new TaskCompletionSource<TResult>();
            cancellationToken.Register(() => tcs.TrySetCanceled(), false);
            var cancellationTask = tcs.Task;

            // Create a task that completes when either the async operation completes,
            // or cancellation is requested.
            var readyTask = await Task.WhenAny(asyncTask, cancellationTask);

            // In case of cancellation, register a continuation to observe any unhandled 
            // exceptions from the asynchronous operation (once it completes).
            // In .NET 4.0, unobserved task exceptions would terminate the process.
            if (readyTask == cancellationTask)
            {
                await asyncTask.ContinueWith(_ => asyncTask.Exception,
                    TaskContinuationOptions.OnlyOnFaulted |
                    TaskContinuationOptions.ExecuteSynchronously);
            }
            return await readyTask;
        }
    }
}