I'm completing a UWP app started by someone else. The app crashes frequently and I always end up in App.g.i.cs at
if (global::System.Diagnostics.Debugger.IsAttached)
global::System.Diagnostics.Debugger.Break();
where I then have to say "no, don't start the debugger" and close 2 windows.
Is there somewhere I could put a big try/catch so that I don't have to restart the app each time this happen? I can't find anything in AppShell or App.
Or do I have to put a try/catch in every single event handler?
If you want to avoid starting the new debugger and restarting the app each time when encountering unhandled exceptions, you can use Application.UnhandledException event and set the Handled property of the event arguments to true like following:
public App()
{
this.InitializeComponent();
this.Suspending += OnSuspending;
this.UnhandledException += (sender, e) =>
{
e.Handled = true;
System.Diagnostics.Debug.WriteLine(e.Exception);
};
}
The UnhandledException event is used to notify the app about exceptions encountered by the XAML framework or by the Windows Runtime in general that have not been handled by app code.
Normally after the UnhandledException event is fired, the Windows Runtime terminates the app because the exception was unhandled. The app code has some control over this: if the UnhandledException event handler sets the Handled property of the event arguments to true, then in most cases the app will not be terminated.
For more info, please see Remarks of Application.UnhandledException event and the blog: Strategies for Handling Errors in your Windows Store Apps.
As far as i know most you cant do what you are trying to do (big try catch block) and for all intents and purposes you shouldn't even consider that possibility.
First try to determine why the app is crashing, on what page, is it when you try to something specific, the same thing everytime and then you can try catch some of the methods on that particular page and determine what's causing the crash
If you want to treat the cause rather than the symptoms, you should enable first-chance exceptions in the debugger settings. Then the debugger should break at the source of the exception, rather than in the global handler. You can then address the root cause of the problems directly.
Shipping an app that has the global handler blindly set every exception as "handled" even when you don't know why it's failing is not a good solution.
You can try/catch in your main app to catch all exceptions. Shown is an example using Xamarin Forms DisplayAlert:
try
{
//throw new Exception("gone and done it");
MyMainProgram();
}
catch (Exception ex)
{
await DisplayAlert("Whoops!", ex.Message, "ok");
throw ex;
}
You can test this by uncommenting the "throw new Exception". Execution stops with an alert you must answer, then continues by throwing the exception to prevent executing corrupted code.
Related
Here's a strange issue I'm facing with a Windows 8.1 XAML application.
A bug in DevExpress controls causes the entire application to crash, despite my implementation of exception handling. DevExpress developers have replicated this particular bug and are working on a solution - this question is about the crash despite error handling and NOT about the DevExpress bug.
The unique thing about this crash is that it breaks on this line in the auto-generated code in App.g.i.cs (as opposed to other exceptions being thrown in other places):
#if DEBUG && !DISABLE_XAML_GENERATED_BREAK_ON_UNHANDLED_EXCEPTION
UnhandledException += (sender, e) =>
{
if (global::System.Diagnostics.Debugger.IsAttached) global::System.Diagnostics.Debugger.Break();
};
#endif
It seems this is triggered when some kind of exception / crash happens in XAML-related mechanisms (but this is just a wild guess on my part)... I don't think the above code is responsible for the "crash to desktop" effect, but it does seem to be a symptom.
My own code for error handling (in App.xaml.cs):
public App()
{
//...
this.UnhandledException += App_UnhandledException;
//...
}
private async void App_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
var ex = e.Exception;
e.Handled = true;
Logger.LoggingError(ex);
await Controls.MessageDialog.Show(ex.Message, Controls.MessageDialog.DialogType.Error, Controls.MessageDialog.DialogButtons.Retry, ElementTheme.Light);
var frame = Window.Current.Content as Frame;
frame.Navigate(typeof(Views.SplashLoading));
}
The error handling attempts to:
log the error
display the error
go back to the start view
Again - this generally works very well for all other purposes. But if ever the breakpoint in App.g.i.cs gets triggered (or would get triggered, if the application is released on client machines) then my error handling fails completely.
Note, that this isn't exclusive to DevExpress controls. It's just that the DevExpress control causes this behavior in a way that can be replicated. Again - if an exception would cause the code in App.g.i.cs be fired, then it seems there's no saving the application.
What could I do to make sure the application keeps going once this unfortunate event occurs and doesn't crash to the desktop?
EDIT:
For reference, this is the error message which occurs when using the DevExpress controls:
System.ArgumentException: The parameter is incorrect.
The value cannot be infinite or Not a Number (NaN).
at Windows.UI.Xaml.Controls.ScrollViewer.ChangeView(Nullable`1 horizontalOffset, Nullable`1 verticalOffset, Nullable`1 zoomFactor, Boolean disableAnimation)
at DevExpress.Core.Native.DXVirtualizingPanel.ScrollElementIntoView(Double elementOffset, Double rowHeight)
at DevExpress.Core.Native.DXVirtualizingPanel.ScrollIntoView(Int32 visibleIndex)
at DevExpress.UI.Xaml.Grid.DataControlBas
Unfortunately that's the full message - it appears the complete stack-trace is missing.
Apparently setting e.Handled = true; does not guarantee that the application won't crash (as described on MSDN):
The Windows Runtime considers exceptions encountered during certain
operations as nonrecoverable, because the Windows Runtime itself will
be in an inconsistent state following these exceptions. For such
exceptions, even if the UnhandledException event handler sets Handled
to true, the app will still be terminated.
However, why does the DevExpress cause such an invalid state with its control is a mystery to me... But at least it solves the question of why the app closes despite the event being handled.
Extra thanks goes to the folks from DevExpress support team, who helped with the case.
In MainFile:
Window window = new MyDialogWindow();
try
{
window.ShowDialog();
}
catch
{
// This is never called !
}
In MyDialogWindow:
private void MyDialogWindow_Closing( object sender, CancelEventArgs e )
{
throw new Exception();
}
It seems that the exception thrown into the closing event handler never reach the catch block of the caller. Do you know why ?
EDIT: I should mention I've checked that MyDialogWindow_Closing is called after I press on the close button.
EDIT2: When listening to AppDomain.CurrentDomain.UnhandledException, the event is fired !
I would guess that you are getting an exception that is not your thrown exception, but instead another exception that is not normally 'caught' by the .Net exception handling umbrella. One such class of exceptions are structured error handling exceptions (SEH) which typically occur when there are issues (usually memory issues, or pointer issues) in unmanaged code that crash in that execution, but can't be bubbled up into the .Net exception handling stream.
Go into your Debug-->Exceptions, and check everything. Then run your program. You will almost certainly find out what your exception truly is.
It can't hurt to look at this question as well which discusses the topic.
Consider the following simple application: a windows form created by a "new C# windows application" sequence in VS that was modified in a following way:
public static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
try
{
Application.Run(new Form1());
}
catch (Exception ex)
{
MessageBox.Show("An unexpected exception was caught.");
}
}
Form1.cs contains the following modifications:
private void Form1_Load(object sender, EventArgs e)
{
throw new Exception("Error");
}
If I press F5 in IDE, then, as I expect, I see a message box saying that exception was caught and the application quits.
If I go to Debug(or Release)/bin and launch the executable, I see the standard "Unhandled exception" window, meaning that my exception handler doesn't work.
Obviously, that has something to do with exception being thrown from a different thread that Application.Run is called from. But the question remains - why the behavior differs depending on whether the application has been run from IDE or from command line?
What is the best practice to ensure that no exceptions remain unhandled in the application?
Normally Application.ThreadException will handle the exception in the Load event. You'll get the ThreadExceptionDialog that offers the Quit and Continue options.
But not when a debugger is attached. The catch clause in the message loop that displays the dialog is intentionally disabled in that case. That's necessary because it would be very difficult to trouble-shoot exceptions if that dialog pops up when you debug a program. Which this catcher no longer active, your catch clause in the Main() method now gets a shot at the exception.
You can make it consistent by using Application.SetUnhandledExceptionMode() in the Main() method. You shouldn't, exceptions really are hard to debug if you do this. If you want to customize exception handling for the UI thread then you should register your own Application.ThreadException handler:
if (!System.Diagnostics.Debugger.IsAttached)
Application.ThreadException += myThreadException;
Trapping unhandled exceptions in worker threads requires a AppDomain.UnhandledException handler. They are not recoverable.
Also beware of a bug in 64-bit Windows, exceptions in the Load event are swallowed without diagnostic when a debugger is attached. Force AnyCPU mode to avoid that trap.
In addition to catching any exceptions thrown inside the Main method you must also handle AppDomain.CurrentDomain.UnhandledException and Application.ThreadException.
Not sure why the behavior differs with and without a debugger attached though.
I am currently writing a winforms application (C#).
I am making use of the Enterprise Library Exception Handling Block, following a fairly standard approach from what I can see. IE : In the Main method of Program.cs I have wired up event handler to Application.ThreadException event etc.
This approach works well and handles the applications exceptional circumstances.
In one of my business objects I throw various exceptions in the Set accessor of one of the objects properties
set {
if (value > MaximumTrim)
throw new CustomExceptions.InvalidTrimValue("The value of the minimum trim...");
if (!availableSubMasterWidthSatisfiesAllPatterns(value))
throw new CustomExceptions.InvalidTrimValue("Another message...");
_minimumTrim = value;
}
My logic for this approach (without turning this into a 'when to throw exceptions' discussion) is simply that the business objects are responsible for checking business rule constraints and throwing an exception that can bubble up and be caught as required. It should be noted that in the UI of my application I do explictly check the values that the public property is being set to (and take action there displaying friendly dialog etc) but with throwing the exception I am also covering the situation where my business object may not be used by a UI eg : the Property is being set by another business object for example. Anyway I think you all get the idea.
My issue is that these exceptions are not being caught by the handler wired up to Application.ThreadException and I don't understand why.
From other reading I have done the Application.ThreadException event and it handler "... catches any exception that occurs on the main GUI thread". Are the exceptions being raised in my business object not in this thread? I have not created any new threads.
I can get the approach to work if I update the code as follows, explicity calling the event handler that is wired to Application.ThreadException. This is the approach outlined in Enterprise Library samples. However this approach requires me to wrap any exceptions thrown in a try catch, something I was trying to avoid by using a 'global' handler to start with.
try
{
if (value > MaximumTrim)
throw new CustomExceptions.InvalidTrimValue("The value of the minimum...");
if (!availableSubMasterWidthSatisfiesAllPatterns(value))
throw new CustomExceptions.InvalidTrimValue("Another message");
_minimumTrim = value;
}
catch (Exception ex)
{
Program.ThreadExceptionHandler.ProcessUnhandledException(ex);
}
I have also investigated using wiring a handler up to AppDomain.UnhandledException event but this does not catch the exceptions either.
I would be good if someone could explain to me why my exceptions are not being caught by my global exception handler in the first code sample. Is there another approach I am missing or am I stuck with wrapping code in try catch, shown above, as required?
As a thought, try adding (fairly early on - i.e. at the start of Main):
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
That said - it seems to work fine for me with or without...
According to MSDN, Application.ThreadException will only be fired if the exception isn't handled. Maybe there is a catch somewhere up the callstack that is handling the exception?
Another option would be to try using AppDomain.UnhandledException instead. It is the same as Application.ThreadException, except it works for all exceptions in the same AppDomain.
If you try to use use
Application.ThreadException
or
AppDomain.CurrentDomain.UnhandledException
the Debugger will catch the exception!
To test these methods you have to start the appication without a debugger.
I'm wondering what the best way is to have a "if all else fails catch it".
I mean, you're handling as much exceptions as possible in your application,
but still there are bound to be bugs, so I need to have something that
catches all unhandled exceptions so I can collect information and store
them in a database or submit them to a web service.
Does the AppDomain.CurrentDomain.UnhandledException event capture everything?
Even if the application is multithreaded?
Side note: Windows Vista exposes native API functions that allow any application
to recover itself after a crash... can't think of the name now... but I'd rather not
use it, as many of our users are still using Windows XP.
I have just played with AppDomain's UnhandledException behavior,
(this is the last stage the unhandled exception is registered at)
Yes, after processing the event handlers your application will be terminated and the nasty "... program stopped working dialog" shown.
:)
You still can avoid that.
Check out:
class Program
{
void Run()
{
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
Console.WriteLine("Press enter to exit.");
do
{
(new Thread(delegate()
{
throw new ArgumentException("ha-ha");
})).Start();
} while (Console.ReadLine().Trim().ToLowerInvariant() == "x");
Console.WriteLine("last good-bye");
}
int r = 0;
void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Interlocked.Increment(ref r);
Console.WriteLine("handled. {0}", r);
Console.WriteLine("Terminating " + e.IsTerminating.ToString());
Thread.CurrentThread.IsBackground = true;
Thread.CurrentThread.Name = "Dead thread";
while (true)
Thread.Sleep(TimeSpan.FromHours(1));
//Process.GetCurrentProcess().Kill();
}
static void Main(string[] args)
{
Console.WriteLine("...");
(new Program()).Run();
}
}
P.S. Do handle the unhandled for Application.ThreadException (WinForms) or DispatcherUnhandledException (WPF) at the higher level.
In ASP.NET, you use the Application_Error function in the Global.asax file.
In WinForms, you use the MyApplication_UnhandledException in the ApplicationEvents file
Both of these functions are called if an unhandled exception occurs in your code. You can log the exception and present a nice message to the user from these functions.
For Winform applications, in addition to AppDomain.CurrentDomain.UnhandledException I also use Application.ThreadException and Application.SetUnhandledExceptionMode (w/ UnhandledExceptionMode.CatchException). This combination seems to catch everything.
On the main thread, you have the following options:
Console or Service application: AppDomain.CurrentDomain.UnhandledException
WinForms application: Application.ThreadException
Web application: Global.asax's Application_Error
For other threads:
Secondary threads have no unhandled-exceptions; use SafeThread
Worker threads: (timer, threadpool) there is no safety net at all!
Bear in mind that these events do not handle exceptions, they merely report them to the application--often when it is far too late to do anything useful/sane about them
Logging exceptions is good, but monitoring applications is better ;-)
Caveat: I am the author of the SafeThread article.
For WinForms, don't forget to attach to the current Thread's unhandled exception event too (especially if you are using multi threading).
Some links on best practices here and here and here (probably the best exception handling article for .net)
There's also a cool thing called ELMAH that will log any ASP.NET errors that occur in a web application. I know you're asking about a Winform App solution, but I felt this could be beneficial to anyone needing this type of thing on a web app. We use it where I work and it's been very helpful in debugging (especially on production servers!)
Here's some features that it has (pulled right off the page):
Logging of nearly all unhandled exceptions.
A web page to remotely view the entire log of recoded exceptions.
A web page to remotely view the full details of any one logged exception.
In many cases, you can review the original yellow screen of death that
ASP.NET generated for a given
exception, even with customErrors mode
turned off.
An e-mail notification of each error at the time it occurs.
An RSS feed of the last 15 errors from the log.
A number of backing storage implementations for the log, including
in-memory, Microsoft SQL Server and
several contributed by the community.
You can monitor most exceptions in that handler even in multithreaded apps, but .NET (starting with 2.0) won't allow you to cancel unhandled exceptions unless you enable the 1.1 compatibility mode. When that happens the AppDomain will be shut down no matter what. The best you could do is launch the app in a different AppDomain so that you can handle this exception and create a new AppDomain to restart the app.
I am using the following approach, which works and reduces greatly the amount of code ( yet I am not sure if there is a better way or what the pitfalls of it might be.
Whenever you call:
I quess the quys giving minuses would be polite enough to clarify their actions ; )
try
{
CallTheCodeThatMightThrowException()
}
catch (Exception ex)
{
System.Diagnostics.StackTrace st = new System.Diagnostics.StackTrace ();
Utils.ErrorHandler.Trap ( ref objUser, st, ex );
} //eof catch
And here is the ErrorHandler code :
Just to make clear- : objUser - is the object modelling the appusers ( you might get info such as domain name , department , region etc. for logging purposes
ILog logger - is the logging object - e.g. the one performing the logging activities
StackTrace st - the StackTrace object giving you debugging info for your app
using System;
using log4net; //or another logging platform
namespace GenApp.Utils
{
public class ErrorHandler
{
public static void Trap ( Bo.User objUser, ILog logger, System.Diagnostics.StackTrace st, Exception ex )
{
if (ex is NullReferenceException)
{
//do stuff for this ex type
} //eof if
if (ex is System.InvalidOperationException)
{
//do stuff for this ex type
} //eof if
if (ex is System.IndexOutOfRangeException)
{
//do stuff for this ex type
} //eof if
if (ex is System.Data.SqlClient.SqlException)
{
//do stuff for this ex type
} //eof if
if (ex is System.FormatException)
{
//do stuff for this ex type
} //eof if
if (ex is Exception)
{
//do stuff for this ex type
} //eof catch
} //eof method
}//eof class
} //eof namesp
In a manged GUI app, by default, exceptions that originate in the GUI thread are handled by whatever is assigned to the Application.ThreadException.
Exceptions that originate in the other threads are handled by AppDomain.CurrentDomain.UnhandledException.
If you want your GUI thread exceptions to work just like your-non GUI ones, so that they get handled by AppDomain.CurrentDomain.UnhandledException, you can do this:
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException);
An advantage to catching the GUI thread exceptions using ThreadException is that you can give the use the options of letting the app continue. To make sure no config files are overriding default behavior, you can call:
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
You are still vulnerable to exceptions from badly behaved native dlls. If a native dll installs its own handler using Win32 SetUnhandledExceptionFilter, it is supposed to save the pointer to the previous filter and call it too. If it doesn't do that, your handler wont' get called.