If you've been using the SQL Server Management Studio that comes with SQL Server 2005 for a while, you might noticed this nice message box that shows all exception messages. Not only it shows the exception message, but also includes hierarchy of all inner exceptions. What's more you can see the technical details of the exception including its call stack. On top of that you can easily copy all this to the Clipboard.
As soon as I've seen this I thought: "I wish I had something like this in my project". But I never got into building this all myself. As it turns out I won't have to. If you look close enough at the SQL Server 2005 download pages or dig deep in the SQL Server 2005 Books Online you can spot a thing called Exception Message Box.
The Exception Message Box is a programmatic component used by all SQL Server graphical tools. It has all functionality of the MessageBox class, but is designed to elegantly handle managed code exception. It allows you to do the following:
- Provide customized button text for up to five buttons. Buttons and the dialog box resize automatically for different text lengths.
- Allow users to easily copy the message title, text, button text, and help links (if any) to the Clipboard or send this information in an e-mail message.
- Display all underlying exceptions and errors in a hierarchical relationship tree when users click Additional Information.
- Allow users to decide whether to display the message when the same exception occurs again.
- Access an online help system by using a help link associated with the exception.
This component is distributed with all editions of SQL Server 2005 except SQL Server 2005 Mobile Edition. It is also available for separate download as part of the Feature Pack for Microsoft SQL Server 2005. The component is contained in single assembly called Microsoft.ExceptionMessageBox.dll and doesn’t have any additional dependencies besides .NET Framework 2.0 itself. By default it installs into GAC. If you have installed SQL Server 2005 SDK, you can also find it in following folder:
c:\Program Files\Microsoft SQL Server\90\SDK\Assemblies
So now, knowing that such interface exists, lets see how we can use it. First we need to add the reference to the above mentioned assembly and add using directive to use the Microsoft.SqlServer.ExceptionMessageBox namespace. Next we add the try-catch block to handle the exception:
try
{
File.OpenRead("c:\\not_existing_file");
}
catch (Exception ex)
{
ExceptionMessageBox box = new ExceptionMessageBox(ex);
box.Show(this);
}
As you can see in the simple case you only need to create the instance of ExceptionMessageBox passing the exception to it's constructor and then call the Show method. This method takes reference to owner (IWin32Window) but you can simply put a null instead if you don't have access to any window from your code. One such situation would be in the global handler for unhandled exceptions such as Application.ThreadException or AppDomain.CurrentDomain.UnhandledException.
If you want to display own error message but also keep the original exception for additional information you should wrap it in new Exception object:
try
{
File.OpenRead("c:\\not_existing_file");
}
catch (Exception ex)
{
ApplicationException exTop = new ApplicationException("Error loading data", ex);
exTop.Source = this.Text;
ExceptionMessageBox box = new ExceptionMessageBox(exTop);
box.Show(this);
}
Here we also change the caption of the message box by changing the Source property on the top exception.
Contrary to its name, the ExceptionMessageBox doesn't restrict to showing exceptions. Like I said above, it has all functionality of the ordinary MessageBox. For example we can use it to present questions:
ExceptionMessageBox box = new ExceptionMessageBox(
"Do you want to save changes in current document?", this.Text,
ExceptionMessageBoxButtons.YesNoCancel,
ExceptionMessageBoxSymbol.Question);
DialogResult result = box.Show(this);
The Show method returns a familiar DialogResult that we can use to process user decision.
However, you don't have to be constrained anymore with only the system icons or the few button combinations available:
ExceptionMessageBox box = new ExceptionMessageBox(
"Do you like my new icon?", this.Text);
box.CustomSymbol = Properties.Resources.MyCustomIcon;
box.SetButtonText("I love it", "It's ugly", "I don't know");
box.Buttons = ExceptionMessageBoxButtons.Custom;
box.DefaultButton = ExceptionMessageBoxDefaultButton.Button3;
box.Show(this);
We can change the icon by assigning a Bitmap to the CustomSymbol property. To change the button captions we need to call SetButtonText method (we can use up to five buttons) and set the Buttons property to ExceptionMessageBoxButtons.Custom to tell the box to use our captions. Additionally, we can specify which button should be treated as default, so when user presses the Enter key this one would be selected.
In this case we can't use the DialogResult returned from the Show method. Instead, use the ExceptionMessageBoxDialogResult value available via the CustomDialogResult property.
As you see ExceptionMessageBox is can be really useful, and offers many interesting features. It can even show a "Don't show again" checkbox so user can decide to whether to show the exception message box for particular error. You can find some more examples in the SQL Server 2005 Books Online.
One thing that I miss however is ability to send the error reports to pre-configured support email address. As I remember this function was included in earlier betas of SQL Server Management Studio, and I guess that for some reason was removed in the final release, but I wish they left it as an option in the component.