Previously in .NET 4.0 you had to either block the current thread until a long-running or IO operation completed (which causes scaling issues) or handle the result in a callback or ContinueWith continuation (hard to read and debug).
C# 5.0 introduced two new keywords used in conjunction with the Task type to simplify asynchronous programming.
asyncmarks a method (or lambda) that can useawait. It usually returns aTaskorTask<T>which represents the status of the operation and any result (async voidexists for event handlers only).awaitwaits for an awaitable such as aTaskand unwraps its result. If the task has not completed yet the method returns control to its caller and resumes later. It can only be used inside anasyncmethod.
Code
csharp
// Using WebRequest for comparison to older styles
var request = WebRequest.Create("https://damieng.com");
using (var response = await request.GetResponseAsync())
using (var stream = response.GetResponseStream())
using (var reader = new StreamReader(stream))
Console.WriteLine(await reader.ReadToEndAsync());
// But you're better off using HttpClient, get httpClient from factory/shared instance
var html = await httpClient.GetStringAsync("https://damieng.com");
Console.WriteLine(html);csharp
var request = WebRequest.Create("https://damieng.com");
using (var response = request.GetResponse())
using (var responseStream = response.GetResponseStream())
using (var reader = new StreamReader(responseStream))
Console.WriteLine(reader.ReadToEnd());csharp
var request = WebRequest.Create("https://damieng.com");
Task.Factory.FromAsync(request.BeginGetResponse, request.EndGetResponse, null)
.ContinueWith(task =>
{
using (var response = task.Result)
using (var stream = response.GetResponseStream())
using (var reader = new StreamReader(stream))
Console.WriteLine(reader.ReadToEnd());
});Notes
WebRequestis obsolete in .NET 6 and later, useHttpClientfor new code- In library code add
.ConfigureAwait(false)to eachawaitwhen you don't need to resume on the original context- This avoids unnecessary context switching and the deadlocks that occur when callers block on the task
- Do not use it in UI code that touches controls after the
await, as the UI must be updated on the original context - ASP.NET Core has no synchronization context so it makes no difference there