The TAP is a new pattern for asynchronous programming in .NET Framework 4.5. It is based on a task, but in this case a task doesn't represent work which will be performed on another thread. In this case, a task is used to represent arbitrary asynchronous operations.
Let's start learning how async
and await
work by creating a Windows Presentation
Foundation (WPF) application that accesses the web using HttpClient
. This kind of network access is ideal for seeing TAP in action. The application will get the contents of a classic book from the web, and will provide a count of the number of words in the book.
Let's go to Visual Studio 2012 and see how to use the async
and await
keywords to maintain a responsive UI by doing the web communications asynchronously.
WordCountAsync
as Solution name.MainWindow.xaml
and adding the following XAML to create a simple user interface containing Button
and TextBlock
:<Window x:Class="WordCountAsync.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="WordCountAsync" Height="350" Width="525"> <Grid> <Button x:Name="StartButton" Content="Start" HorizontalAlignment="Left" Margin="219,195,0,0" VerticalAlignment="Top" Width="75" RenderTransformOrigin="-0.2,0.45" Click="StartButton_Click"/> <TextBlock x:Name="TextResults" HorizontalAlignment="Left" Margin="60,28,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Height="139" Width="411"/> </Grid> </Window>
MainWindow.xaml.cs
. Go to the Project and add a reference to System.Net.Http
.using
directives to the top of your MainWindow
class:using System; using System.Linq; using System.Net.Http; using System.Threading.Tasks; using System.Windows;
MainWindow
class, add a character
array constant that will be used to split the contents of the book into a word array.char[] delimiters = { ' ', ',', '.', ';', ':', '-', '_', '/', 'u000A' };
StartButton
and add the async
modifier to the method signature to indicate that this will be a async
method. Please note that async
methods that return void
are normally only used for event handlers, and should be avoided.private async void StartButton_Click(object sender, RoutedEventArgs e) { }
async
method called GetWordCountAsync
that returns Task<int>
. This method will create HttpClient
and call its GetStringAsync
method to download the book contents as a string. It will then use the Split
method to split the string into a wordArray
. We can return the count of the wordArray
as our return
value.public async Task<int> GetWordCountAsync() { TextResults.Text += "Getting the word count for Origin of Species... "; var client = new HttpClient(); var bookContents = await client.GetStringAsync(@"http://www.gutenberg.org/files/2009/2009.txt"); var wordArray = bookContents.Split(delimiters, StringSplitOptions.RemoveEmptyEntries); return wordArray.Count(); }
Click
event handler will just call GetWordCountAsync
with the await
keyword and display the results to TextBlock
.private async void StartButton_Click(object sender, RoutedEventArgs e) { var result = await GetWordCountAsync(); TextResults.Text += String.Format("Origin of Species word count: {0}",result); }
In the TAP, asynchronous methods are marked with an async
modifier. The async
modifier on a method does not mean that the method will be scheduled to run asynchronously on a worker thread. It means that the method contains control flow that involves waiting for the result of an asynchronous operation, and will be rewritten by the compiler to ensure that the asynchronous operation can resume this method at the right spot.
Let me try to put this a little more simply. When you add the async
modifier to a method, it indicates that the method will wait on an asynchronous code to complete. This is done with the await
keyword. The compiler actually takes the code that follows the await
keyword in an async
method and turns it into a continuation that will run after the result of the async
operation is available. In the meantime, the method is suspended, and control returns to the method's caller.
If you add the async
modifier to a method, and then don't await
anything, it won't cause an error. The method will simply run synchronously.
An async
method can have one of the three return types: void
, Task
, or Task<TResult>
. As mentioned before, a task in this context doesn't mean that this is something that will execute on a separate thread. In this case, task is just a container for the asynchronous work, and in the case of Task<TResult>
, it is a promise that a result value of type TResult
will show up after the asynchronous operation completes.
In our application, we use the async
keyword to mark the button click event handler as asynchronous, and then we wait for the GetWordCountAsync
method to complete by using the wait
keyword.
private async void StartButton_Click(object sender, RoutedEventArgs e) { StartButton.Enabled = false; var result = await GetWordCountAsync(); TextResults.Text += String.Format("Origin of Species word count: {0}", .................. result); StartButton.Enabled = true; }
The code that follows the await
keyword, in this case, the same line of code that updates TextBlock
, is turned by the compiler into a continuation that will run after the integer
result is available.
If the Click
event is fired again while this asynchronous task is in progress, another asynchronous task is created and awaited. To prevent this, it is a common practice to disable the button that is clicked.
It is a convention to name an asynchronous method with an Async
postfix, as we have done with GetWordCountAsync
.
18.218.48.62