Supporting Winforms: Logging and Sending Diagnostic Information
See the Visual Studio 2005 (.NET 2.0) attached code here
A common problem when working with smart clients or any client that you deploy to an end users desktop is the ability to diagnose problems that arise in the users application. Because the application is not hosted on a server, the various problems that exist for a given user can vary. Worse, users typically cannot remember what actions they performed to cause the error.
A solution:
To aid us, we must create some level of communication back to the software vendor, allowing the vendor some insight into various attributes of the client application. The following attributes are amongst the most important things we'd like to know about a client-side application.
- What modules and assemblies are loaded?
- What is the configuration of the system its running on?
- What does the application look like and what state is it in?
- What did the user do to cause the application to fail?
We can solve this problem by creating a framework that uses a little reflection to allow us to "peek" into the forms and properties of the currently running application.
To get modules, system information and state, we can look at the AppDomain.CurrentDomain.GetAssemblies() method to get the loaded assemblies.
To get the system information, we can easily get the properties of the SystemInformation class.
To get the state of the app (how it looks), it is a good idea to get the properties of the form. To achieve this, we can use reflection to look at every property of every control and write out the details of all the controls (recursively) on the form. This will give us a good idea of what we're looking at.
Lastly, if we have built our application with a decent amount of instrumentation (such as a trace call at the beginning (and maybe end) of all our big operations or form events, we can get a good picture of what the user has done by caching those Trace.Write calls so we can write them out in the event of failure. Better still, we can wrap Trace.Write so that every call provides us additional information, such as which thread we're calling from.
To demonstrate this, you can download the code sample I've provided with this blog entry. Run the Winforms application and play with the buttons and textboxes. Then click the "Help -> Send Diagnostics" menu item to write "test.txt" to your working directory. This will be a dump of all the data mentioned above. Ideally, you would send this through email or a remoting call to your support group.
In addition, catching the Application.ThreadException (see the Program class in the winforms test) will allow you to log this data prior to a crash, allowing you to figure out what went wrong without user intervention.
Please note: To use this code in your own example, you must add the trace listener as seen in the app.config of the winforms project.
Code Sample: .NET 2.0 Code Sample is available here