Author: Jeff Noble
I have run into a problem while trying to deal with exceptions in the Composite UI Application Block (CAB). It seems that while in the IDE in debug mode, everything works as expected. However, when running without debugging (or running the .exe directly) unexpected behavior occurs.
Reproducing the unexpected
- Create a new CAB project (I use the Guidance package to do this). I am calling mine CABSample
- Add a foundational Module. I called mine SampleFoundation.
- Create a View in the Foundational Model. I called mine SampleView.
- Add the following Code in the load event of the Module.cs file in the SampleView project:
SampleView view = _rootWorkItem.SmartParts.Get<SampleView>(“SampleView”);
if (view == null)
{
view = _rootWorkItem.SmartParts.AddNew<SampleView>();
}view.Dock = DockStyle.Fill;
_rootWorkItem.Workspaces[WorkspaceNames.RightWorkspace].Show(view); - Drag a button onto the SampleView control. I will be bypassing the whole MVP model for this example to keep things simple.
- Double click the button and add the following into the click event (yes I know it’s a divide by zero error):
int a = 1;
int b = 2;
int c = 0;
int d = a + b / c; - Set the project to Release Mode and Run the project (without debugging) , and click the button.
You now see an error instead of the expected dialog box. The reason that this is not the expected behavior is that there is code in the shell application to handle unexpected errors. The code looks like this (and it should already be in place in your project):
In Shellapplication.cs – RunInReleaseMode():
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(AppDomainUnhandledException);
In Shellapplication.cs – AppDomainUnhandledException():
private static void AppDomainUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
HandleException(e.ExceptionObject as Exception);
}
private static void HandleException(Exception ex)
{
if (ex == null)
return;
THIS LINE WILL FAIL WITHOUT AN EXCEPTION POLICY SO COMMENT IT OUT IF YOU HAVE NOT SET ONE UP
//ExceptionPolicy.HandleException(ex, “Default Policy”);
MessageBox.Show(“An unhandled exception occurred, and the application is terminating. For more information, see your Application event log.”);
Application.Exit();
}
So why if we have our unhandled exceptions handled does the event NOT fire? You would expect to see a nice dialog box, but instead it just blows up.
The Fix
The fix was a mediocre band in the 80′s, oh sorry, I digress… <grin>. The fix is to replace the AppDomain.CurrentDomain.UnhandledException code with other code that actually will do what we want. Here is how to implement the changes. If you want you can add these changes to the SCSF guidance that builds your projects, but I have not done that so I leave that to you. I may post that code in another article if I feel up to it.
Delete the nasty code
Remove the following from ShellApplication.cs in the RunInReleaseMode():
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(AppDomainUnhandledException);
Also, remove the try catch block in the RunInReleaseMode() method. (I show it here commented, but you should remove the commented lines).
//try
//{
new ShellApplication().Run();
//}
//catch (Exception ex)
//{
//HandleException(ex);
//}
Add the Fixed Code
Instead add in it’s place in RunInReleaseMode():
Application.ThreadException +=
new ThreadExceptionEventHandler(AppDomainUnhandledException);
Then you need to make one more change. Make the following changes to AppDomainUnhandledException():
private static void AppDomainUnhandledException(object sender, ThreadExceptionEventArgs e)
{
HandleException(e.Exception);
}
Now if you run the application in Release mode, you will see that you get the results you expect. A nice dialog box. This took me a long time to figure out, so I hope it helps everyone on the planet. Ok, not that many people, but congrats for finding this on my remote little blog.
-Jeff
3 Comments
Thanks a lot, this addressed my unsolvable problem perfectly.
Hello,
I use the Enterprise Library Exception Handling block to log exceptions fired in my CAB application. This works fine before the user logs into my application. In fact, after a successful login, I create a new Windows Identity object which I associate to my application’s current thread. And, its after this process, that my exception handler fails to write information about exceptions in the event log.
Could anybody propose a solution, please ? Thanks
Shah
Sounds like it could be a permissions problem of some sort. Weird that it happens only after authentication. I would d/l processmon from the bottom of this page: http://www.microsoft.com/technet/sysinternals/FileAndDisk/processmonitor.mspx and use it to look for problems. Check to see if there is a permission problem accessing the registry. The registry requires rights to use the event log. I would start with that first.
-Savij