Over the years there have been multiple ways to write asynchronous code in .NET with async/await
being the latest attempt to make it less error-prone and more developer friendly.
We started the asynchronous journey in .NET 1.0 with the Asynchronous Programming Model where you had to write a Begin
and End
method following a specific pattern:
This was improved in .NET 2.0 with the introduction of the Event-Based Asynchronous pattern(focussing mainly on client applications) in combination with the SynchronizationContext
simplifying the scheduling of work on the UI thread:
In .NET 4.0 the System.Threading.Tasks.Task
type was introduced, a data structure that represents the eventual completion of some asynchronous operation:
And finally we arrived at async/await
where we use the power of iterators to generate a state machine that handles all the continuations and callbacks for us. This allows us to write asynchronous code in a way that almost feel as synchronous simplifying the mental model and readability of our code:
If you want to learn about all the details, check out the amazingly detailed post by Stephen Toub: How Async/Await Really Works in C# - .NET Blog (microsoft.com)
More information: Asynchronous programming - C# | Microsoft Learn