Async, await, exception…

Async and await keywords are used to perform asynchronous code. This article shows how to handle exception in such code.
Imagine we have simple application with button. When button is clicked data is read from any external source. We try to make this read asynchronous to not block GUI.

        /// <summary>
        /// Simple button click handler.
        /// </summary>
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            
            ReadDataAsync();
        }

        /// <summary>
        /// Simulate data reading (asynchronous).
        /// </summary>
        private async void ReadDataAsync()
        {
            var result = await Task.Run(() =>
            {
                Thread.Sleep(2000);
                return "My data";
            });

            //UI update must be executed on GUI thread
            mainTextBlock.Text = result;
        }

Now imagine that ReadDataAsync throws an exception.
One way to handle this exception is to write catch in ReadDataAsync body.

        /// <summary>
        /// Simple button click handler.
        /// </summary>
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                ReadDataAsync();
            }
            catch (Exception)
            {
                mainTextBlock.Text = "Reading failed.";
            }
        }

        /// <summary>
        /// Simulate data reading (asynchronous).
        /// </summary>
        private async void ReadDataAsync()
        {
            try
            {
                var result = await Task.Run(() =>
                {
                    throw new Exception("Unknown exception");
                    Thread.Sleep(2000);
                    return "My data";
                });

                //UI update must be executed on GUI thread
                mainTextBlock.Text = result;
            }
            catch (Exception)
            {
                mainTextBlock.Text = "Reading failed.";
            }
        }

Notice, the way shown below is not correct (!) and exception is still not handled. Catch in place where async method is raised won’t fix the problem.

        /// <summary>
        /// Simple button click handler.
        /// </summary>
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                ReadDataAsync();
            }
            catch (Exception)
            {
                mainTextBlock.Text = "Reading failed.";
            }
        }

        /// <summary>
        /// Simulate data reading (asynchronous).
        /// </summary>
        private async void ReadDataAsync()
        {
                var result = await Task.Run(() =>
                {
                    throw new Exception("Unknown exception");
                    Thread.Sleep(2000);
                    return "My data";
                });

                //UI update must be executed on GUI thread
                mainTextBlock.Text = result;
        }

Notice, that if we change the ReadDataAsync return type from void to Task, the exception will be swallowed, nevertheless we don’t have catch anywhere. We won’t know what is the type of the exception etc.

        /// <summary>
        /// Simple button click handler.
        /// </summary>
        private async void Button_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                ReadDataAsync();
            }
            catch (Exception)
            {
                mainTextBlock.Text = "Reading failed.";
            }
        }


        /// <summary>
        /// Simulate data reading (asynchronous).
        /// </summary>
        private async Task ReadDataAsync()
        {
            var result = await Task.Run(() =>
            {
                throw new Exception("Unknown exception");
                Thread.Sleep(2000);
                return "My data";
            });

            //UI update must be executed on GUI thread
            mainTextBlock.Text = result;
        }

But we can solve the problem. Generally we should avoid async void methods, always when possible, to get rid of such behaviour. Let’s change the code above to edit the return type of our method to async Task. Then await method and catch possible exceptions.

        /// <summary>
        /// Simple button click handler.
        /// </summary>
        private async void Button_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                var data = await ReadDataAsync();
                //update GUI on UI thread
				mainTextBlock.Text = data;
            }
            catch (Exception)
            {
                mainTextBlock.Text = "Reading failed.";
            }
        }

        /// <summary>
        /// Simulate data reading (asynchronous).
        /// </summary>
        private async Task<string> ReadDataAsync()
        {
            var result = await Task.Run(() =>
            {
                throw new Exception("Unknown exception");
                Thread.Sleep(2000);
                return "My data";
            });

            return result;
        }
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s