C# Catching exception which is occurring on Thread

2019-04-20 20:50发布

问题:

I am investigating some crashes in my application caused by a Win32 exception, and I have narrowed it down that it must be occurring in the threadpool which is taking care of the EventLog.EntryWrittenEventHandler event handler in my application. I set this up like this:

// Create the event log monitor
eventLog.Log = "Application";
eventLog.EnableRaisingEvents = true;
eventLog.EntryWritten += new EntryWrittenEventHandler(EventLogMonitor);

EventLogMonitor is the handler for my event. I am wondering does anybody have any ideas as to where I could find out whats causing this exception. It seems that to listen for events a ThreadPoolWaitOrTimerCallback is being set up, which wouldn't have any of my code on it, and if the exception is occurring on this I just cant see how to deal with this problem. Any help is really appreciated!!

Here is the output of !clrstack in WinDBG:

0:008> !clrstack
OS Thread Id: 0x106c (8)
ESP       EIP     
049df1c8 7756f871 [HelperMethodFrame: 049df1c8] 
049df26c 73ce6fa0 System.Diagnostics.EventLog.get_OldestEntryNumber()
049df27c 73bf24ed System.Diagnostics.EventLog.CompletionCallback(System.Object)
049df2c4 73bf0fe4 System.Diagnostics.EventLog.StaticCompletionCallback(System.Object, Boolean)
049df2f4 744fc3b8 System.Threading._ThreadPoolWaitOrTimerCallback.WaitOrTimerCallback_Context(System.Object, Boolean)
049df300 744fc373 System.Threading._ThreadPoolWaitOrTimerCallback.WaitOrTimerCallback_Context_f(System.Object)
049df304 7400027f System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
049df31c 744fc477 System.Threading._ThreadPoolWaitOrTimerCallback.PerformWaitOrTimerCallback(System.Object, Boolean)
049df4ac 74991b5c [GCFrame: 049df4ac] 

In case it helps, my application is just checking the event ID of every entry written to the event log, and if it matches one of a certain set of ID's then I log it. The crashes happen quiet rarely, and the exception is a System.ComponentModel.Win32 exception with message 'Access is denied'. That sounds like it could be a permissions issue but why would it work ok for a certain period and then suddenly crash with this.

回答1:

If I understand you correctly (it would help if you pass the stacktrace that leads you to the conclusion that the exception is happening inside a threadpool thread), then just wrap your code of EventLogMonitor in a try/catch block.

Example:

void EventLogHandler(object sender, EventArgs args)
{
   try
   {
      // Your original code.
   }
   catch (Exception ex)
   {
      // Log or Write "ex" to the console. Set a breakpoint, whatever.

      throw;
   }
}

UPDATE: after your update it looks as if the exception is indeed not raised from inside your handler, but before it is even called inside the EventLog class.

You could try registering a handler with the AppDomain.UnhandledException event and do your logging/handling in there. Note that this will not allow you to suppress or "change" or wrap the exception, but merely to log it somewhere for diagnostic purposes.

If you just want to inspect the exception once (or on occasion), you should try using the SOS-extension's !PrintException command in WinDBG.

UPDATE 2: after further investigation I find it rather strange that the exception bubbles up all. Your stacktrace suggests you're using .NET 3.5 (or earlier, but not 4.) and looking at the EventLog class in Reflector you can see that the whole handling of the EventWrittenHandler, including the preamble code that seems to cause the exception, is wrapped in one big "try/catch(Exception)/catch" block. Funny.



回答2:

Subscribe to Application.ThreadException in your Program.cs as follows to be able to catch the exceptions that are not in main thread.

static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.ThreadException += Application_ThreadException;
        try
        {
            Application.Run(new MainForm());
        }
        catch (Exception e)
        {
            HandleException(e);
        }
    }

    static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
    {
        HandleException(e.Exception);
    }


回答3:

  1. If you can, use Tasks in System.Threading.Tasks.
  2. Try, where action is performing what you want.

    ThreadPool.QueueUserWorkItem(state =>
    {
        try
        {
            action();
        }
        catch (Exception ex)
        {
            OnException(ex);
        }
    });
    


回答4:

Not sure what kind of Application this is, so in a general case, if you're having no luck, try hooking into the AppDomain in which the code is running. If you don't have multiple domains, you can try:

AppDomain.CurrentDomain.FirstChanceException += Handler

or

AppDomain.CurrentDomain.UnhandledException += Handler