async samples 9: Migration from Existing APIs

The ninth set of samples discusses migrating existing asynchronous programming models to the upcoming async syntax.  The first sample shows how you can wrap code that uses the existing Asynchronous Programming Model library to use the new async features.

        public async void AsyncFromAPM()
{
var response = await WebRequest.Create("http://www.weather.gov").
GetResponseAsync();
var stream = response.GetResponseStream();
var buffer = newbyte[1024];
int count;
while ((count = await ReadAsync(stream, buffer, 0, 1024)) > 0)
{
Console.Write(Encoding.UTF8.GetString(buffer, 0, count));
}
}

publicstatic Task<int> ReadAsync(Stream stream, byte[] buffer,
int offset, int count)
{
var tcs = new TaskCompletionSource<int>();
stream.BeginRead(buffer, offset, count, iar =>
{
try { tcs.TrySetResult(stream.EndRead(iar)); }
catch (Exception exc) { tcs.TrySetException(exc); }
}, null);
return tcs.Task;
}
The interesting code here is in the ReadAsync method. It creates a TaskCompletionSource that carries the result. The ReadAsync method returns the task, which can be awaited by the caller. Once the read has completed, the calling method continues execution.
 
If you’ve used the current Asynchronous Programming Model, you should appreciate how much more readable and concise this version is.
 
The next sample shows how you would convert a more extensive asynchronous operation to use the proposed syntax. This version leverages the new async features in the language in a method that supports cancellation, and reports progress:
 
        private CancellationTokenSource cts;

public async Task AsyncFromEAP()
{
cts = new CancellationTokenSource();
var progress = new EventProgress<DownloadProgressChangedEventArgs>();
progress.ProgressChanged += (sender, e) =>
{ ProgressBar.Value = e.Value.ProgressPercentage; };

try
{
WriteLinePageTitle(await DownloadStringAsync(new Uri("http://www.weather.gov"),
cts.Token, progress));
}
catch
{
Console.WriteLine("Downloading canceled.");
}
}

publicstatic Task<string> DownloadStringAsync(Uri address,
CancellationToken cancel, IProgress<DownloadProgressChangedEventArgs> progress)
{
// Create the task to be returned
var tcs = new TaskCompletionSource<string>(address);
var webClient = new WebClient();

// Register the cancellation token
var ctr = cancel.Register(webClient.CancelAsync);

// Setup the callback event handlers
webClient.DownloadProgressChanged += (s, e) => progress.Report(e);
webClient.DownloadStringCompleted += (s, e) =>
{
ctr.Dispose();
if (e.Error != null) tcs.TrySetException(e.Error);
elseif (e.Cancelled) tcs.TrySetCanceled();
else tcs.TrySetResult(e.Result);
};

// Start the async operation.
webClient.DownloadStringAsync(address, tcs);

// Return the task that represents the async operation
return tcs.Task;
}

The heavy lifting here is done by the DownloadStringAsync method. It puts initializes the cancellation callback, the progress reporting callback, and the completion callback. The last thing is does is to start the download, and return the task that can be awaited.
 
More importantly, look at the calling code, the AsyncFromEAP() method. The new syntax and language features makes this method much more readable than the equivalent code would be using previous features.
 
The final sample in this section shows how you can convert an existing synchronous method to an asynchronous method:
 
ublic staticvoid CopyTo(Stream source, Stream destination)
{
// Old synchronous implementation:

var buffer = newbyte[0x1000];
int bytesRead;
long totalRead = 0;
while ((bytesRead = source.Read(buffer, 0, buffer.Length)) > 0)
{
destination.Write(buffer, 0, bytesRead);
totalRead += bytesRead;
}
}

publicstatic async Task CopyToAsync(Stream source, Stream destination,
CancellationToken cancellationToken,
IProgress<long> progress)
{
// New asynchronous implementation:

var buffer = newbyte[0x1000];
int bytesRead;
long totalRead = 0;
while ((bytesRead = await source.ReadAsync(buffer, 0, buffer.Length)) > 0)
{
await destination.WriteAsync(buffer, 0, bytesRead);
cancellationToken.ThrowIfCancellationRequested(); // cancellation support
totalRead += bytesRead;
progress.Report(totalRead); // progress support
}
}

The final sample in this set shows how easy it is to convert an existing synchronous method to async you use the new syntax. It’s as simple as calling ReadAsync instead of Read, and WriteAsync instead of Write. For bonus points, this conversion includes an IProgress delegate so that it can report progress.
 
The new version is no more complicated. The code isn’t longer. That’s one of the reasons I really like the direction that C# async support is taking.
Created: 4/4/2011 12:02:13 PM

Current Projects

I create content for .NET Core. My work appears in the .NET Core documentation site. I'm primarily responsible for the section that will help you learn C#.

All of these projects are Open Source (using the Creative Commons license for content, and the MIT license for code). If you would like to contribute, visit our GitHub Repository. Or, if you have questions, comments, or ideas for improvement, please create an issue for us.

I'm also the president of Humanitarian Toolbox. We build Open Source software that supports Humanitarian Disaster Relief efforts. We'd appreciate any help you can give to our projects. Look at our GitHub home page to see a list of our current projects. See what interests you, and dive in.

Or, if you have a group of volunteers, talk to us about hosting a codeathon event.