When writing an application, you may come across a situation where some method takes time to execute. This long-running task may cause your application to hang or a user interface to freeze until it completes. The reason for this is because it is executing synchronously, which means that it is running on the main thread and blocking that thread until the operation completes. For years, developers have worked at overcoming this by performing these long-running tasks asynchronously.
Many aspects of asynchronous programming are covered in detail in chapter 19, so this basic concept will be touched on here. Asynchronous programming involves performing long-running tasks, or those that would cause the main thread to pause, on another thread. This other thread would execute in the background, independent of the main thread, which would continue running unhindered. Since both threads are executing concurrently, they are considered asynchronous.
While this approach allows for a much more responsive application, it is somewhat more convoluted and difficult to follow in code and manage. The reason for this is because you are responsible for knowing when the background thread(s) is/are completed and for managing data and synchronicity across them.
The .NET framework has always supported asynchronous programming by providing asynchronous methods in classes where they make the most sense. This would typically be classes that included methods that access data such as reading ...