async Samples 6: Declaring async methods

So far, we’ve only discussed calling async methods. The next set of samples discusses how to declare async methods.

I’m going to discuss these three samples in a different order than they appear on Lucian’s site. I think a different order will make it easier to understand the concepts. Let’s start with an async method that has a void return:

        public
        void AsyncReturnVoid()
{
Console.WriteLine("*** BEFORE CALL ***");
VoidReturningMethod();
Console.WriteLine("*** AFTER CALL ***");
}

private async void VoidReturningMethod()
{
WriteLinePageTitle(await new WebClient().DownloadStringTaskAsync(
new Uri("http://www.weather.gov")));
WriteLinePageTitle(await new WebClient().DownloadStringTaskAsync(
new Uri("http://www.weather.gov/climate/")));
WriteLinePageTitle(await new WebClient().DownloadStringTaskAsync(
new Uri("http://www.weather.gov/rss/")));
}

The output from this sample appears below:

*** BEFORE CALL ***
*** AFTER CALL ***
Page title: NOAA's National Weather Service
Page title: NOAA's National Weather Service - National Climate
Page title: RSS Libraries and Podcast - NOAA's National Weather Service

This is a “fire and forget” scenario. VoidReturningMethod returns to the caller as soon as it encounters its first await. However, the VoidReturningMethod is still executing asynchronously. That’s why you see the output in the order you see above.

Next, let’s examine how to declare an async method that returns a Task<T>. The next sample shows that scenario:

        public async void AsyncReturnTaskOfT()
{
Console.WriteLine("*** BEFORE CALL ***");
Console.WriteLine(await TaskOfStringReturningMethod());
Console.WriteLine("*** AFTER CALL ***");
}

private async Task<string> TaskOfStringReturningMethod()
{
StringBuilder sb = new StringBuilder();
sb.AppendLine(GetPageTitle(await new WebClient().DownloadStringTaskAsync(
new Uri("http://www.weather.gov"))));
sb.AppendLine(GetPageTitle(await new WebClient().DownloadStringTaskAsync(
new Uri("http://www.weather.gov/climate/"))));
sb.AppendLine(GetPageTitle(await new WebClient().DownloadStringTaskAsync(
new Uri("http://www.weather.gov/rss/"))));
return sb.ToString();
}

This code does await all the async operations. The output is in the order you’d expect: all the page titles are printed between the “Before Call” and the “After Call” lines. The AsyncReturnTaskOfT() method awaits the result of the TaskOfStringReturningMethod().

Finally, let’s examine the sample that returns a Task:

        public async void AsyncReturnTask()
{
Console.WriteLine("*** BEFORE CALL ***");
await TaskReturningMethod();
Console.WriteLine("*** AFTER CALL ***");
}

private async Task TaskReturningMethod()
{
WriteLinePageTitle(await new WebClient().DownloadStringTaskAsync(
new Uri("http://www.weather.gov")));
WriteLinePageTitle(await new WebClient().DownloadStringTaskAsync(
new Uri("http://www.weather.gov/climate/")));
WriteLinePageTitle(await new WebClient().DownloadStringTaskAsync(
new Uri("http://www.weather.gov/rss/")));
}

This one works similar to the second sample above. The TaskReturningMethod returns a Task as soon as it encounters it’s first await (when it downloads the page at www.weather.gov). And yet, when you look at the output, you’ll see this:

*** BEFORE CALL ***
Page title: NOAA's National Weather Service
Page title: NOAA's National Weather Service - National Climate
Page title: RSS Libraries and Podcast - NOAA's National Weather Service
*** AFTER CALL ***

This one gets a bit complicated. Here’s what happens:

  1. The TaskReturningMethod executes until the first await.
  2. Control returns to AsynReturningMethod, which is awaiting that Task.
  3. The first download finishes, and that first Task executes its Continuation: printing the first title, starting the next download. There’s another await there.
  4. Control returns to TaskReturningMethod, which is still awaiting. Once the second page finishes downloading, its continuation executes: printing the second title, and starting the final download. Control returns to the (still) awaiting AsyncReturningMethod.
  5. That final download finishes, and now its continuation executes: printing the final page title.
  6. Having finished all the async tasks, control returns for the last time to AsyncReturningMethod. The async tasks have all completed, so that method is done Awaiting. Now “After Call” gets printed.

The mechanics are rather complicated, but conceptually the behavior is what you want: The three downloads all happen asynchronously. Anytime code awaits that action, that control flow stops until the awaited action completes. In the end, the code executes, more or less, in the same order as an imperative version of the same code, but many parts of it can execute asynchronously.

Thanks to Chris Marinos and Jay Wren who helped me work through the flow of this sample.

Created: 3/25/2011 12:07:05 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.