Software Exception Flow Analysis for WPF C# Asynchronous...

18
Software Exception Flow Analysis for WPF C# Asynchronous Programs Using Microsoft Visual Studio Summary Recently, I was working on an implementation of a new software product feature based on asynchronous computation for a project that was upgraded from Visual Studio (VS) 2008 to 2012 and targeted .Net 4.5 instead of .Net 3.5. One of my concerns was dealing with software exceptions. I decided to test what happens in WPF-based asynchronous programs that lack of proper exception handling. This paper gives a few examples, to demonstrate what you can expect from unreliable code. Here you will find: Code examples four asynchronous techniques process-wide exception handlers Views of propagation of exceptions results of tracing exceptions thrown at different places in code examples analysis of information collected in Visual Studio Debugger Microsoft Visual Studio features Exception Assistant settings Debugger Dialog Boxes The paper will be useful for those who are in the process of examining asynchronous techniques and different .NET, C# and VS Debugger features. Asynchronous Code Following are four examples of C# classes that implement different asynchronous techniques allowed in different C#\.NET versions. Each class has its specific CalculateAsync method called from a WPF button control handler. A callback was used to make all examples similar even if known implementation patterns do not use them. The code has embedded throw statements (shown in red that have been commented out) to simulate exceptions. The Common Language Runtime creates an object that presents an exception. Exception handling is based on these objects and protected blocks of code. The generated exceptions then go unhandled in programmed examples logic. This is minimal code used to demonstrate unhandled software exception flows. Variables inData and outData are included in the code only to express that the asynchronous actions may use input data and return results. Production level error checking has been omitted.

Transcript of Software Exception Flow Analysis for WPF C# Asynchronous...

Software Exception Flow Analysis for WPF C# Asynchronous Programs

Using Microsoft Visual Studio

Summary Recently, I was working on an implementation of a new software product feature based on asynchronous computation for a project that was upgraded from Visual Studio (VS) 2008 to 2012 and targeted .Net 4.5 instead of .Net 3.5. One of my concerns was dealing with software exceptions. I decided to test what happens in WPF-based asynchronous programs that lack of proper exception handling. This paper gives a few examples, to demonstrate what you can expect from unreliable code. Here you will find:

• Code examples four asynchronous techniques process-wide exception handlers

• Views of propagation of exceptions results of tracing exceptions thrown at different places in code examples analysis of information collected in Visual Studio Debugger

• Microsoft Visual Studio features Exception Assistant settings Debugger Dialog Boxes

The paper will be useful for those who are in the process of examining asynchronous techniques and different .NET, C# and VS Debugger features.

Asynchronous Code Following are four examples of C# classes that implement different asynchronous techniques allowed in different C#\.NET versions. Each class has its specific CalculateAsync method called from a WPF button control handler. A callback was used to make all examples similar even if known implementation patterns do not use them. The code has embedded throw statements (shown in red that have been commented out) to simulate exceptions. The Common Language Runtime creates an object that presents an exception. Exception handling is based on these objects and protected blocks of code. The generated exceptions then go unhandled in programmed examples logic. This is minimal code used to demonstrate unhandled software exception flows. Variables inData and outData are included in the code only to express that the asynchronous actions may use input data and return results. Production level error checking has been omitted.

Event Based Asynchronous Code The simplified code in Listing 1 shows an implementation class that has a single <MethodName>Async method and a corresponding <MethodName>CompletedEventHandler method. Listing 1. Event Based Asynchronous Code Example.

BackgroundWorker Thread Based Asynchronous Code The simplified code in Listing 2 shows an implementation class that has a single <MethodName>Async method that explicitly creates and runs a BackgroundWorker thread. Listing 2. BackgroundWorker Thread Based Asynchronous Code Example.

Task Based Asynchronous Code The simplified code in Listing 3 shows an implementation class that has a single <MethodName>Async method that explicitly creates and starts a Task<ReturnType> available with the .Net Framework 4.0.

Listing 3. Task Based Asynchronous Code Example.

Async\Await Based Asynchronous Code The simplified code in Listing 4 shows an implementation class using the C# 5.0 “async” and “await” keywords that are used by the compiler to build a state machine. The word “async” is not applied to the corresponding calling method so that all examples are similar. In contrast to the three previous examples, in this example, the Calculation () method runs on the main GUI thread base on the provided Synchronization Context. Care must be taken to not include CPU-bound code in the Calculation () method because it will block the main GUI thread, which is exactly the issue that is avoided with asynchronous code. Listing 4. Async\Await Based Asynchronous Code Example.

Calling Code The simplified code in Listing 5 shows possible options of calling of above examples. The callback method is used in all four examples Listing 5. Calling Code Example.

Last Resort It is extremely important to catch unhandled exceptions from different parts of the code to prevent running the application in a “wrong” state. What you will do in “global” handlers for unhandled exceptions depends on your design. Suggestions on processing these can be found online. The objective of this paper is to demonstrate which exceptions can be caught and where they will be caught.

The XAML code in Listing 6 in App.xaml shows how to specify event handlers for Application.Startup and Application.DispatcherUnhandledException events. Listing 6. Specifying Event Handlers Example.

The code in Listing 7 for App class in App.xaml.cs shows how to specify event handlers for unhandled exceptions. All handlers here are presented only for demonstration and do not provide steps for graceful shutdown.

Listing 7. Specifying Handlers for Unhandled Exceptions Example.

Know Your Debugger

Setting Debugger To set how the Debugger will help you in exceptions’ investigation, you need to navigate to Options Dialog Box (Fig. 1). In VS 2008 you need to navigate to Tools\Options… and in VS 2012 you will find it under Debug\Options and Settings…

Figure 1.Visual Studio Options Dialog Box.

In the Options Dialog Box, choose General under the Debugging node. In the right pane, there is the “Enable the exception assistant” check box. The Exception Assistance dialog box is used (MSDN) for managed code only instead of the “old” Exception dialog box and gives more information. If this check box is checked, you may also check the dependent “Unwind the call stack on unhandled exceptions” check box. This functionality automatically unwinds the call stack to the topmost frame in your solution where the exception was thrown and then by pressing a function key to continue you will generate the exception repeatedly.

Using Debugger In Table 1 we collected trace informationforone of the possible unhandled runtime exceptions that occurs in application code. We simulated this exception by embedding a “throw new Exception

("1");”statement in our demonstration code (see “Event Based Asynchronous Code” section above).Table 1illustrates behavior of MS Visual Studio Debugger when the exception’s text message“1” is thrown. The Figures below this table demonstrate appearance of VS Debuggers’ Dialog Boxes. #

Subscribed for Unhandled Exception Event

Options\ Debugging\ General

MS Visual Studio and .NET Versions

AppDomain. Unhandled Exception Event

Application. Dispatcher Unhandled Exception Event

Enable the Exception Assistant and Unwind the Call Stack

2008

.Net 3.5

2012

.Net 4.5

1 Yes Yes Checked Assistant DlgBox(Fig. 2) ApplUnhndlEx Hndl AppDomUnhndl Ex Hndl Assistant DlgBox(Fig. 2) Program has exited

Assistant DlgBox(Fig. 7) FirstChance Ex Hndl Appl UnhndlEx Hndl Assistant DlgBox(Fig. 6) FirstChance Ex Hndl(sys) AppDomUnhndlEx Hndl Assistant DlgBox(Fig. 6) Program has exited

2 Yes Yes Unchecked Ex DlgBox(Fig. 3) ApplUnhndlEx Hndl AppDomUnhndlEx Hndl Ex DlgBox(Fig. 4) Program has exited

FirstChance Ex Hndl Appl UnhndlEx Hndl FirstChance Ex Hndl(sys) AppDom Unhndl Ex Hndl Ex DlgBox(Fig. 8) Program has exited

3 No No Checked Start loop Assistant DlgBox(Fig. 2) Continue in loop

Start loop Assistant DlgBox(Fig. 7) FirstChanceEx Hndl Assistant DlgBox(Fig.7) Continue in loop

4 No No Unchecked Ex DlgBox(Fig. 5) Program has exited

FirstChance Ex Hndl Ex DlgBox(Fig.9) Program has exited

Table 1. Demonstrates dependence of an Exception Flow on the use of Exception Assistant Dialog Box and Presence of Handlers for Unhandled Exceptions As seen from this Table and Figures below: • VS 2012 has improved appearance of Dialog Boxes. • VS 2012 Assistant Dialog Box is different depends on situation it will appear. • When there are no handlers for unhandled exceptions and VS Debugger is set to unwind call stack,

the Assistant Dialog Box will appear in a loop until the user stops debugging. • The Assistant Dialog Boxes are different when there are registered handlers for unhandled

exceptions and when they are not registered. • Figure 10 shows examples of Message and InnerException values produced by a UnobservedTask

exception.

Figure 2. VS2008 Exception Assistant Dialog Box

Figure 3. VS2008 Old Exception Dialog Box (first)

Figure 4. VS2008 Old Exception Dialog Box (second)

Figure 5. VS2008 Old Exception Dialog Box (third)

Figure 6. VS2012 Exception Assistant Dialog Box (first)

Figure 7. VS2012 Exception Assistant Dialog Box (second)

Figure8. VS2012 Exception Dialog Box (first)

Figure 9. VS2012 Exception Dialog Box (second)

Figure 10. VS2012 Dialog Box with a Message for a UnobservedTask exception Tracing Unhandled Exceptions In Table 2 trace information was collected for exception flows generated at different places of asynchronous processing. Exception number (column 3) corresponds to a value of error message that was used to initialize a thrown instance of the Exception type. This exception is simulated by embedding a “throw new Exception ("<Value>");” statement in the demonstration code above. Table 2 illustrates where unhandled exception can be handled and what happen to the application if those handlers do not modify unhandled exceptions’ “normal” flow. In other words, the graceful exit was intentionally not used. We subscribed to AppDomain.CurrentDomain.UnhandledException and Application.DispatcherUnhandledException events. Also, we subscribed to FirstChanceException event available since .Net 4.0 for debugging purpose to show exception’s message before common language runtime locates a handler.

# Async Technique

Exception #

MS Visual Studio and .NET Versions 2008

.NET3.5 2012

.NET 4.5 1 Event 1 Appl Unhndl Ex Hndl

AppDom Unhndl Ex Hndl Crash

FirstChance Ex Hndl Appl Unhndl Ex Hndl FirstChance Ex Hndl AppDom Unhndl Ex Hndl Crash

2 AppDom Unhndl Ex Hndl Crash

FirstChance Ex Hndl FirstChance Ex Hndl AppDom Unhndl Ex Hndl Crash

3 AppDom Unhndl Ex Hndl Crash

FirstChance Ex Hndl AppDom Unhndl Ex Hndl Crash

4 AppDom Unhndl Ex Hndl Crash

FirstChance Ex Hndl AppDom Unhndl Ex Hndl Crash

2 Bckgrd Worker Thread

11 Appl Unhndl Ex Hndl AppDom Unhndl Ex Hndl Crash

FirstChance Ex Hndl Appl Unhndl Ex Hndl FirstChance Ex Hndl AppDom Unhndl Ex Hndl Crash

12 Appl Unhndl Ex Hndl AppDom Unhndl Ex Hndl Crash

FirstChance Ex Hndl FirstChance Ex Hndl(my rethrow) Appl Unhndl Ex Hndl FirstChance Ex Hndl AppDom Unhndl Ex Hndl Crash Or without rethrow FirstChance Ex Hndl Application continues running

3 Task 21 - FirstChance Ex Hndl Appl Unhndl Ex Hndl FirstChance Ex Hndl AppDom Unhndl Ex Hndl Crash

22 - FirstChance Ex Hndl CalculateFaulted Method Application continues running Or without CalculateFalted() FirstChance Ex Hndl UnobservedTask Ex Hndl Application continues running

23 - FirstChance Ex Hndl CalculateFaulted1 Method Application continues running

4 Async/ Await

31 - FirstChance Ex Hndl UnobservedTask Ex Hndl Application continues running

32 - FirstChance Ex Hndl FirstChance Ex Hndl(on await) UnobservedTask Ex Hndl Application continues running Or if await oper is guarded by a try block FirstChance Ex Hndl FirstChance Ex Hndl(on await) Application continues running

33 - FirstChance Ex Hndl Calculate() will be executed UnobservedTask Ex Hndl Application continues running

Table 2. Demonstrates exception flows generated at different places of asynchronous processing. As seen from this table: • “Appl Unhndl Ex Hndl” is used to present the Application_DispatcherUnhandledException() method

and “AppDom Unhndl Ex Hndl” is used to represent the AppDomain_UnhandledException() method. The former handler is called when no handlers are found to handle an exception on the GUI thread. In the example, code was not provided to inform CLR that the exception was handled. Therefore, the AppDomain.UnhandledException event is always raised for default domain and will be caught in the later handle.

• Catch First Chance exception before the Common Language Runtime is searching for exception handlers if you want to see what is happening when it is being thrown.

• UnobservedTaskException event is fired on the Garbage Collector (GC) Finalizer Thread when Garbage Collector runs, an exception not caught and Task.Wait() or Task<T>.Result is accessed. When an application continues to run there is no calls to Application_DispatcherUnhandledException and\or AppDomain_UnhandledException().

• When an application continues to run without programmer’s written code to react to an exception, it means that some corrupted or wrong data could be used.

Closing Note This paper was written to show what one can expect from exceptions in asynchronous WPF C# programs. Adding “global” handlers is easy. It may prevent the application from running with wrong data and\or from its “hard” crash when the program is running in an unanticipated situation. It also helps with debugging. In asynchronous programs that use Tasks you should not count on a UnobservedTask exception that is complementary to unhandled exceptions because the GC will run and execute the finalizer undeterministically. It is helpful to use this during development; however, the production code has to catch exceptions at the right place.

Acknowledgments I would like to thank all colleagues with whom I had numerous discussions about asynchronous programming and debugging. I also thank Debie Urycki for proof reading and suggestions on corrections.

About the Author

Boris Eligulashvili is a Systems Software Architect at Viewray, Inc. a medical device company developing advanced radiation therapy technology for the treatment of cancer. In his career he has implemented many innovative software solutions for various software development projects. Boris is reachable by email at [email protected].