Exception handling in asynchronous programming

Exception handling in asynchronous programming has always been a challenge. This was especially true in the catch blocks. As of C# 6, you are now allowed to write asynchronous code inside the catch and finally block of your exception handlers.

Getting ready

The application will simulate the action of reading a logfile. Assume that a third-party system always makes a backup of the logfile before processing it in another application. While this processing is happening, the logfile is deleted and recreated. Our application, however, needs to read this logfile on a periodic basis. We, therefore, need to be prepared for the case where the file does not exist in the location we expect it in. Therefore, we will purposely omit the main logfile, so that we can force an error.

How to do it…

  1. Create a text file and two folders to contain the logfiles. We will, however, only create a single logfile in the BackupLog folder. The MainLog folder will remain empty:
    How to do it…
  2. In our AsyncDemo class, write a method to read the main logfile in the MainLog folder:
    private async Task<int> ReadMainLog()
    {
        var bigFile = File.OpenRead(@"C:	empLogMainLog	askFile.txt");
        var bigFileBuffer = new byte[bigFile.Length];
        var readBytes = bigFile.ReadAsync(bigFileBuffer, 0, (int)bigFile.Length);
        await readBytes.ContinueWith(task =>
        {
            if (task.Status == TaskStatus.RanToCompletion)
                Console.WriteLine("Main Log RanToCompletion");
            else if (task.Status == TaskStatus.Faulted)
                Console.WriteLine("Main Log Faulted");
    
            bigFile.Dispose();
        });
        return await readBytes;
    }
  3. Create a second method to read the backup file in the BackupLog folder:
    private async Task<int> ReadBackupLog()
    {
        var bigFile = File.OpenRead(@"C:	empLogBackupLog	askFile.txt");
        var bigFileBuffer = new byte[bigFile.Length];
        var readBytes = bigFile.ReadAsync(bigFileBuffer, 0, (int)bigFile.Length);
        await readBytes.ContinueWith(task =>
        {
            if (task.Status == TaskStatus.RanToCompletion)
                Console.WriteLine("Backup Log RanToCompletion");
            else if (task.Status == TaskStatus.Faulted)
                Console.WriteLine("Backup Log Faulted");
    
            bigFile.Dispose();
        });
        return await readBytes;
    }

    Note

    In actual fact, we would probably only create a single method to read the logfiles, passing only the path as a parameter. In a production application, creating a class and overriding a method to read the different logfile locations would be a better approach. For the purposes of this recipe, however, we specifically wanted to create two separate methods so that the different calls to the asynchronous methods are clearly visible in the code.

  4. We will then create a main ReadLogFile() method that tries to read the main logfile. As we have not created the logfile in the MainLog folder, the code will throw a FileNotFoundException. It will then run the asynchronous method and await that in the catch block of the ReadLogFile() method (something that was impossible in the previous versions of C#), returning the bytes read to the calling code:
    public async Task<int> ReadLogFile()
    {
        int returnBytes = -1;
        try
        {
            Task<int> intBytesRead = ReadMainLog();
            returnBytes = await ReadMainLog();
        }
        catch (Exception ex)
        {
            try
            {
                returnBytes = await ReadBackupLog();
            }
            catch (Exception)
            {
                throw;
            }
        }
        return returnBytes;
    }
  5. If not done so in the previous recipe, add a button to your Windows Forms application's Forms Designer. On the winformAsync Forms Designer, open Toolbox and select the Button control, which is found under the All Windows Forms node:
    How to do it…
  6. Drag the button control onto the Form1 designer:
    How to do it…
  7. With the button control selected, double-click on the control to create the click event in the code behind. Visual Studio will insert the event code for you:
    namespace winformAsync
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
    
            }
        }
    }
  8. Change the button1_Click event and add the async keyword to the click event. This is an example of a void returning an asynchronous method:
    private async void button1_Click(object sender, EventArgs e)
    {
    
    }
  9. Next, we will write the code to create a new instance of the AsyncDemo class and attempt to read the main logfile. In a real-world example, it is at this point that the code does not know that the main logfile does not exist:
    private async void button1_Click(object sender, EventArgs e)
    {
        Console.WriteLine("Read backup file");
        Chapter6.AsyncDemo oAsync = new Chapter6.AsyncDemo();
        int readResult = await oAsync.ReadLogFile();
        Console.WriteLine("Bytes read = " + readResult);
    }
  10. Running your application will display the Windows Forms application:
    How to do it…
  11. Before clicking on the button1 button, ensure that the Output window is visible:
    How to do it…
  12. From the View menu, click on the Output menu item or type Ctrl + Alt + O to display the Output window. This will allow us to see the Console.Writeline() outputs as we have added them to the code in the Chapter6 class and in the Windows application.
  13. To simulate a file not found exception, we deleted the file from the MainLog folder. You will see that the exception is thrown, and the catch block runs the code to read the backup logfile instead:
    How to do it…

How it works…

The fact that we can await in catch and finally blocks allows developers much more flexibility, because asynchronous results can consistently be awaited throughout the application. As you can see from the code we wrote, as soon as the exception was thrown, we asynchronously read the file read method for the backup file.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.37.126