Simplification — I've created an empty AWS Lambda project with .net CORE :
This is the default empty lambda function project :
I want to catch all exception in the app , globally.
So I've created a method that generates an exception, and added a global application handler :
Complete code :
public class Function
{
void CreateException()
{
var z = 0;
var a = 2 / z;
Console.Write(a);
}
public Function()
{
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
}
public void FunctionHandler(object input, ILambdaContext context)
{
CreateException();
}
private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
// � It never gets here
}
}
The problem is that the exception is raised , but it never fires CurrentDomain_UnhandledException
Question:
Is this the right way of catching global exceptions ? and why doesn't CurrentDomain_UnhandledException invoked when there is an unhandled exception ?
While I cannot answer why this isn't working, I can tell you I have done as a workaround.
The workaround I have used is to wrap my FunctionHandler in a try/catch. Since this is the only entrypoint in the lambda function, anything that gets thrown in here will be caught...effectively acting like a global handler for my purposes.
public void FunctionHandler(object input, ILambdaContext context)
{
try
{
CreateException();
}
catch (Exception e)
{
// Handle your 'uncaught' exceptions here and/or rethrow if needed
Console.WriteLine(e);
throw;
}
}
You would likely want to rethrow so that:
AWS will retry the function again, then you can send it DeadLetterQueue after X retries
You get the exception in your CloudWatch Logs
Related
In Windows Forms when an exception is thrown from a call to Control.Invoke or Control.BeginInvoke and it is unhandled by any catch block, it can be handled by a control- or application-level handler via the Windows.Forms.Application.ThreadException event. Its handler takes an EventArgs with a property Exception, which is the exception thrown. However, under the hood, Windows.Forms.Control (undesirably) strips off all but the most inner exception, per this answer.
Found this blog post on it as well, but it doesn't suggest any workaround.
(This currently is causing me to get a trivial stack trace in my error logs--a stack trace that tells me the innermost details of , but there is no calling code mentioned and no way to figure out the code location of such an error.)
Is there a workaround? Is there any way to get all the outer exceptions in my application event handler (which is logging unexpected exceptions for troubleshooting)?
The only suggestion I have found seems to be to catch the exception inside the invoked code and stuff some of its info into Exception.Data, perhaps in a new exception--but if I knew the outer code that caused the exception, I could just fix the bug rather than logging it. Instead, how could I do this globally without wrapping a try-catch around every candidate block of code?
This is admittedly a hack, but it's the best solution I was able to come up with which supports both global exception handling in WinForms and all exceptions, even with inner exceptions.
In the Program.cs:
internal static class Program
{
[STAThread]
static void Main()
{
ApplicationConfiguration.Initialize();
AppDomain.CurrentDomain.FirstChanceException += CurrentDomain_FirstChanceException;
Application.ThreadException += Application_ThreadException;
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException, true);
Application.Run(new MyMainForm());
}
private static void CurrentDomain_FirstChanceException(object sender, FirstChanceExceptionEventArgs e)
{
_outermostExceptionCache.AddException(e.Exception);
}
private static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
{
Exception exception = null;
if (e?.Exception != null)
exception = _outermostExceptionCache.GetOutermostException(e.Exception);
// Handle exception
}
private static OutermostExceptionCache _outermostExceptionCache = new();
}
And for that you'll need the OutermostExceptionCache class:
public class OutermostExceptionCache
{
public void AddException(Exception ex)
{
if ((ex != null) && (ex is not TargetInvocationException))
{
Exception innermostException = GetInnermostException(ex);
lock (_syncRoot)
{
RemoveOldEntries();
_cache[innermostException] = new CacheEntry(ex);
}
}
}
public Exception GetOutermostException(Exception ex)
{
Exception innermostException = GetInnermostException(ex);
Exception outermostException = null;
lock (_syncRoot)
{
if (_cache.TryGetValue(innermostException, out CacheEntry entry))
{
outermostException = entry.Exception;
_cache.Remove(innermostException);
}
else
{
outermostException = ex;
}
}
return outermostException;
}
private void RemoveOldEntries()
{
DateTime now = DateTime.Now;
foreach (KeyValuePair<Exception, CacheEntry> pair in _cache)
{
TimeSpan timeSinceAdded = now - pair.Value.AddedTime;
if (timeSinceAdded.TotalMinutes > 3)
_cache.Remove(pair.Key);
}
}
private Exception GetInnermostException(Exception ex)
{
return ex.GetBaseException() ?? ex;
}
private readonly object _syncRoot = new();
private readonly Dictionary<Exception, CacheEntry> _cache = new();
private class CacheEntry
{
public CacheEntry(Exception ex)
{
Exception = ex;
AddedTime = DateTime.Now;
}
public Exception Exception { get; }
public DateTime AddedTime { get; }
}
}
The way this works is by watching every exception, as it is thrown, before the runtime even bubbles the exception up to the nearest catch block. Each time an exception is thrown, it is added to a cache, indexed by the innermost (i.e. base) exception. Therefore, when an exception is caught and a new exception is thrown, with the original one as its inner exception, the cache is updated with that outer exception. Then, when Application.ThreadException event handler is provided with the unwrapped, innermost, exception, the handler can look up the outermost one from the cache.
Note: Since even locally-caught exceptions will get added to the cache (and therefore never removed via a call to GetOutermostException), it timestamps each one and automatically ditches any that are older than 3 minutes. That's an arbitrary timeout which can be adjusted as needed. If you make the timeout too short, it could cause problems with debugging since it can cause the exception handling to revert to handling only the innermost exception if you pause the process too long in the debugger (after the exception is thrown but before it is handled).
Is there a way to implement a global exception handling with MVVM pattern. In my existing case, whenever an error is happening inside of ViewModel, the application does not crash, just "hides" the rest of bindings that happen after the code that caused the error (certainly this is very misleading for end user, and not true, and should never happen that way). I would not like to implement try catch for every operation in the viewModel, and I dont like the silent way of error exception, I would really love to implement a way for WPF app to handle global errors. Is there a way to do it with the MVVM?
After a long battle finally I have found a very easily way to implement handling exceptions inside of ViewModel. While creating a BindingListener that inherits from DefaultTraceListener is certainly a great way to find your binding errors during the debug mode, this will not catch exceptions that have occurred inside a ViewModel when running solution is standard mode. But AppDomain.CurrentDomain.FirstChanceException will.
App.xaml.cs:
AppDomain.CurrentDomain.FirstChanceException += new EventHandler<System.Runtime.ExceptionServices.FirstChanceExceptionEventArgs>(CurrentDomain_FirstChanceException);
private void CurrentDomain_FirstChanceException(object sender, FirstChanceExceptionEventArgs e)
{
Dispatcher.BeginInvoke(new Action(() => MessageBox.Show("Error Occurred \n\r" + e.Exception.Message + "\n\r" + e.Exception.StackTrace, "ERROR", MessageBoxButton.OK, MessageBoxImage.Error)));
}
You could wrap each method in a lamba. Something like this...
public async void DoSomething()
{
await RunSafe(async () =>
{
await model.DoSomething();
await model.DoSomethingElse();
await model.DoLastThing();
});
}
private async Task RunSafe(Func<Task> del, [CallerMemberName] String methodName = "")
{
try
{
Log.Info("Executing {0}", methodName);
await del();
}
catch (Exception ex)
{
StatusMessage = string.Format("Error in {0}(...): {1}\r\n{2}", methodName, ex.Message, ex.ToString());
Log.Error("Error occured in plug in.", ex);
}
}
Look into deriving the DefaultTraceListener class. I've seen people derive their own BindingListener from it, and override the WriteLine method to throw your own exceptions.
You can just spin one of these up during your application start, and it should go on it's own:
public class BindingListener : DefaultTraceListener`
{
public BindingListener()
{
PresentationTraceSources.Refresh();
PresentationTraceSources.DataBindingSource.Listeners.Add(this);SourceLevels.Error;
}
public override void WriteLine(string message){...}
}
Note: This may not do exactly what you want out of the box, you may have to modify a few props.
Related to this question, I would like to force CLR to let my .NET 4.5.2 app catch Corrupted State Exceptions, for the sole purpose of logging them and then terminating the application. What's the correct way to do this, if I have catch (Exception ex) at several places around the app?
So, after I specify the <legacyCorruptedStateExceptionsPolicy> attribute, if I understood correctly, all the catch (Exception ex) handlers will catch exceptions like AccessViolationException and happily continue.
Yeah, I know catch (Exception ex) is a Bad Idea™, but if CLR would at least put the correct stack trace into the Event Log, I would be more than happy to explain to the customer that his server app failing fast at 1AM and being offline for the night is a good thing. But unfortunately, CLR logs an unrelated exception into the Event Log and then closes the process so that I cannot find out what actually happened.
The question is, how to make this happen, process wide:
if the exception thrown is a Corrupted State Exception:
- write the message to the log file
- end the process
(Update)
In other words, this would probably work for most exceptions in a simple app:
[HandleProcessCorruptedStateExceptions]
[SecurityCritical]
static void Main() // main entry point
{
try
{
}
catch (Exception ex)
{
// this will catch CSEs
}
}
But, it won't work for:
Unhandled app domain exceptions (i.e. thrown on non-foreground threads)
Windows Service apps (which don't have an actual Main entry point)
So it seems like <legacyCorruptedStateExceptionsPolicy> is the only way to make this work, in which case I don't know how to fail after logging the CSE?
Instead of using <legacyCorruptedStateExceptionsPolicy> it would be better to use [HandleProcessCorruptedStateExceptions] (and [SecurityCritical]) as stated here:
https://msdn.microsoft.com/en-us/magazine/dd419661.aspx
Following that, your Main method should look something like this:
[HandleProcessCorruptedStateExceptions, SecurityCritical]
static void Main(string[] args)
{
try
{
...
}
catch (Exception ex)
{
// Log the CSE.
}
}
But be aware that this doesn't catch the more serious exceptions like StackOverflowException and ExecutionEngineException.
Also finally of involved try blocks will not be executed:
https://csharp.2000things.com/2013/08/30/920-a-finally-block-is-not-executed-when-a-corrupted-state-exception-occurs/
For other unhandled appdomain exceptions you can use :
AppDomain.CurrentDomain.UnhandledException
Application.Current.DispatcherUnhandledException
TaskScheduler.UnobservedTaskException
(Please do a search for the details when a specific handler is appropriate for your situation. TaskScheduler.UnobservedTaskException for example is a bit tricky.)
If you don't have access to the Main method, you can also mark your AppDomain exception handler to catch the CSE:
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
...
[HandleProcessCorruptedStateExceptions, SecurityCritical]
private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
// AccessViolationExceptions will get caught here but you cannot stop
// the termination of the process if e.IsTerminating is true.
}
The last line of defense could be an unmanaged UnhandledExceptionFilter like this:
[DllImport("kernel32"), SuppressUnmanagedCodeSecurity]
private static extern int SetUnhandledExceptionFilter(Callback cb);
// This has to be an own non generic delegate because generic delegates cannot be marshalled to unmanaged code.
private delegate uint Callback(IntPtr ptrToExceptionInfo);
And then somewhere at the beginning of your process:
SetUnhandledExceptionFilter(ptrToExceptionInfo =>
{
var errorCode = "0x" + Marshal.GetExceptionCode().ToString("x2");
...
return 1;
});
You can find more information about the possible return codes here:
https://msdn.microsoft.com/en-us/library/ms680634(VS.85).aspx
A "specialty" of the UnhandledExceptionFilter is that it isn't called if a debugger is attached. (At least not in my case of having a WPF app.) So be aware of that.
If you set all the appropriate ExceptionHandlers from above, you should be logging all exceptions that can be logged. For the more serious exceptions (like StackOverflowException and ExecutionEngineException) you have to find another way because the whole process is unusable after they happened. A possible way could perhaps be another process that watches the main process and logs any fatal errors.
Additional hints:
In the AppDomain.CurrentDomain.UnhandledException you can safely cast the e.ExceptionObject to Exception without having to worry - at least if you don't have any IL code that throws other objects than Exception: Why is UnhandledExceptionEventArgs.ExceptionObject an object and not an Exception?
If you want to suppress the Windows Error Reporting dialog, you can take a look here: How to terminate a program when it crashes? (which should just fail a unit test instead of getting stuck forever)
If you have a WPF application with multiple dispatchers you can also use a Dispatcher.UnhandledException for the other dispatchers.
Thanks to #haindl for pointing out that you can also decorate handler methods with the [HandleProcessCorruptedStateExceptions]1 attribute, so I made a little test app just to confirm if things really work as they are supposed to.
1 Note: Most answers state that I should also include the [SecurityCritical] attribute, although in the tests below omitting it didn't change the behavior (the [HandleProcessCorruptedStateExceptions] alone seemed to work just fine). However, I will leave both attributes below since I am presuming all these folks knew what they were saying. That's a school example of "Copied from StackOverflow" pattern in action.
The idea is, obviously, to remove the <legacyCorruptedStateExceptionsPolicy> setting from app.config, i.e. only allow our outermost (entry-level) handler(s) to catch the exception, log it, and then fail. Adding the setting will allow your app to continue, if you catch the exception in some inner handler, and this is not what you want: the idea is just to get the accurate exception info and then die miserably.
I used the following method to throw the exception:
static void DoSomeAccessViolation()
{
// if you have any questions about why this throws,
// the answer is "42", of course
var ptr = new IntPtr(42);
Marshal.StructureToPtr(42, ptr, true);
}
1. Catching exceptions from Main:
[SecurityCritical]
[HandleProcessCorruptedStateExceptions]
static void Main(string[] args)
{
try
{
DoSomeAccessViolation();
}
catch (Exception ex)
{
// this will catch all CSEs in the main thread
Log(ex);
}
}
2. Catching all exceptions, including background threads/tasks:
// no need to add attributes here
static void Main(string[] args)
{
AppDomain.CurrentDomain.UnhandledException += UnhandledException;
// throw on a background thread
var t = new Task(DoSomeAccessViolation);
t.Start();
t.Wait();
}
// but it's important that this method is marked
[SecurityCritical]
[HandleProcessCorruptedStateExceptions]
private static void UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
// this will catch all unhandled exceptions, including CSEs
Log(e.ExceptionObject as Exception);
}
I would recommend using just the latter approach, and removing the [HandleProcessCorruptedStateExceptions] from all other places to make sure the exception doesn't get caught at the wrong place. I.e. if you have a try/catch block somewhere and an AccessViolationException is thrown, you want CLR to skip the catch block and propagate to the UnhandledException before ending the app.
Is party over? not so fast
Microsoft: "Use application domains to isolate tasks that might bring down a process."
The program below will protect your main application/thread from unrecoverable failures without risks associated with use of HandleProcessCorruptedStateExceptions and <legacyCorruptedStateExceptionsPolicy>
public class BoundaryLessExecHelper : MarshalByRefObject
{
public void DoSomething(MethodParams parms, Action action)
{
if (action != null)
action();
parms.BeenThere = true; // example of return value
}
}
public struct MethodParams
{
public bool BeenThere { get; set; }
}
class Program
{
static void InvokeCse()
{
IntPtr ptr = new IntPtr(123);
System.Runtime.InteropServices.Marshal.StructureToPtr(123, ptr, true);
}
// This is a plain code that will prove that CSE is thrown and not handled
// this method is not a solution. Solution is below
private static void ExecInThisDomain()
{
try
{
var o = new BoundaryLessExecHelper();
var p = new MethodParams() { BeenThere = false };
Console.WriteLine("Before call");
o.DoSomething(p, CausesAccessViolation);
Console.WriteLine("After call. param been there? : " + p.BeenThere.ToString()); //never stops here
}
catch (Exception exc)
{
Console.WriteLine($"CSE: {exc.ToString()}");
}
Console.ReadLine();
}
// This is a solution for CSE not to break your app.
private static void ExecInAnotherDomain()
{
AppDomain dom = null;
try
{
dom = AppDomain.CreateDomain("newDomain");
var p = new MethodParams() { BeenThere = false };
var o = (BoundaryLessExecHelper)dom.CreateInstanceAndUnwrap(typeof(BoundaryLessExecHelper).Assembly.FullName, typeof(BoundaryLessExecHelper).FullName);
Console.WriteLine("Before call");
o.DoSomething(p, CausesAccessViolation);
Console.WriteLine("After call. param been there? : " + p.BeenThere.ToString()); // never gets to here
}
catch (Exception exc)
{
Console.WriteLine($"CSE: {exc.ToString()}");
}
finally
{
AppDomain.Unload(dom);
}
Console.ReadLine();
}
static void Main(string[] args)
{
ExecInAnotherDomain(); // this will not break app
ExecInThisDomain(); // this will
}
}
I have a sync function such as the following function that generate an IO error (I delete the detail to make it simple):
public override void SyncFunction()
{
throw new IOException("test");
}
and I used it in this way:
try
{
await Task.Run(() => this.SyncFunction());
}
catch (Exception ex)
{
MessageBox.Show("Error:"+Environment.NewLine + ex.Message);
}
But when I run the application, the catch block doesn't get called, but I am getting a message that application crashed. What is the problem and how can I fix it?
The code as you described it should handle the exception just fine.
However, the thing that would crash your application is an exception thrown inside an async void method as the exception has no Task to be stored inside.
So, my guess is that SyncFunction actually looks more like this:
public override async void SyncFunction()
{
throw new IOException("test");
}
And when you invoke it the exception is posted to a ThreadPool thread and that crashes the application.
If that's the case, don't use async void unless in a UI event handler and make sure you handle such exceptions by registering to the AppDomain.CurrentDomain.UnhandledException event.
Update: I've filed a bug report on Microsoft Connect: https://connect.microsoft.com/VisualStudio/feedback/details/568271/debugger-halting-on-exception-thrown-inside-methodinfo-invoke#details
If you can reproduce this problem on your machine, please upvote the bug so it can be fixed!
Ok I've done some testing and I've reduced the problem to something very simple:
i. Create a method in a new class that throws an exception:
public class Class1 {
public void CallMe() {
string blah = null;
blah.ToLower();
}
}
ii. Create a MethodInfo that points to this method somewhere else:
Type class1 = typeof( Class1 );
Class1 obj = new Class1();
MethodInfo method = class1.GetMethod( "CallMe" );
iii. Wrap a call to Invoke() in a try/catch block:
try {
method.Invoke( obj, null ); // exception is not being caught!
} catch {
}
iv. Run the program without the debugger (works fine).
v. Now run the program with the debugger. The debugger will halt the program when the exception occurs, even though it's wrapped in a catch handler that tries to ignore it. (Even if you put a breakpoint in the catch block it will halt before it reaches it!)
In fact, the exception is happening when you run it without the debugger too. In a simple test project it's getting ignored at some other level, but if your app has any kind of global exception handling, it will get triggered there as well. [see comments]
This is causing me a real headache because it keeps triggering my app's crash-handler, not to mention the pain it is to attempt to debug.
I can reproduce this on my .NET 4 box, and you're right -- it only happens on .NET 4.0.
This smells very much like a bug to me, and should go on MS Connect. Major bummer if this is tripping your crash handler. Sounds like a non-pleasing way to work around this is to wrap the invoked method inside its own handler. :-(
One thing I can not reproduce, though, is tripping the crash handler. Here's my program:
namespace trash {
public class Class1 {
public void CallMe() {
string blah = null;
blah.ToLower();
}
}
class Program {
static void Main(string[] args) {
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
var class1 = typeof(Class1);
var method = class1.GetMethod("CallMe");
try {
var obj = new Class1();
method.Invoke(obj, null); // exception is not being caught!
}
catch (System.Reflection.TargetInvocationException) {
Console.Write("what you would expect");
}
}
static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) {
Console.Write("it would be horrible if this got tripped but it doesn't!");
}
}
}
You can't catch all exceptions. There's a few assumptions in your example. You are, for instance, assuming the exception was raised on the calling thread. Catching unhandled exceptions on other threads depends on which runtimes you're using (console, winforms, WPF, ASP.Net, etc).
Additionally, calls to System.Environment.FailFast() do not generate any handlable condition - the process is effectively terminated with no chance for intervention.