0

I am handling top level exceptions in the main entry point of a Windows Form. I want to get access to the calling method/assembly which caused the exception in my handler. I have a feeling I will have to use the trace for this but I am not sure where.

Module Program
  Sub Main()
    Try
      AddHandler AppDomain.CurrentDomain.UnhandledException, Function(sender, e) ExceptionHandler.Handle(sender, DirectCast(e.ExceptionObject, Exception))
      AddHandler Application.ThreadException, Function(sender, e) ExceptionHandler.Handle(sender, e.Exception)
      Application.Run(ApplicationBase)
    Catch ex As Exception
      MessageBox.Show("Handled Exception")
    End Try
  End Sub
End Module

Public Class ApplicationBase
  Public Sub MethodA()
    'Causes an exception
    File.ReadAllLines("")
  End Sub
End Class

Public Class ExceptionHandler

  Public Shared Function Handle(sender As Object, e As Exception)
    Dim t As Type = sender.GetType()
    'Retrieve the calling method here?
    Dim callingMethod = "MethodA"
    Return True
  End Function

End Class

The object coming through as the sender is a thread, I was trying to see if this would be the assembly/object type which the call caused an exception.

My question is how do I get the method name/info and at a push the object name/assembly from within the "handle" method, if it is possible?

EDIT:

Although the e.ToString() will present method names - I am looking for access to the a list of methodinfo/the assemblies/the types to which the exception was caused like reflection and then I can get version numbers of .DLL's etc. - I may be dreaming here but it's something I would like to know if it is possible?

EDIT 2:

I tried e.TargetSite which for MethodA() exception returns the method info of File.ReadAllLines() I am looking for the Class method which causes the exception, so the method info would be MethodA - Although this is a lot closer than I would of thought I would get.

LukeHennerley
  • 6,344
  • 1
  • 32
  • 50

3 Answers3

2

If you want to know which method threw the exception you can use the Exception.TargetSite property; it returns a MethodBase.

If the method that throws this exception is not available and the stack trace is not a null reference (Nothing in Visual Basic), TargetSite obtains the method from the stack trace. If the stack trace is a null reference, TargetSite also returns a null reference.

If you want to walk the stack trace at the time of the exception to find say a method in your code (as opposed to a method in library code) you will have to analyze the stack trace yourself.

You can get the stack trace of an exception:

Dim stackTrace = new StackTrace(ex)

You can get a single stack frame by index:

Dim stackFrame = stackTrace.GetFrame(index)

You can get information from the stack frame:

Dim method = stackFrame.GetMethod()

You then have to come up with an algorithm that walks the stack trace from top to bottom looking for the first frame that satisfies your criteria for being the stack frame you want to report. Here is a very simple algorithm that finds the first frame that is inside the executing assembly.

Dim stackTrace = new StackTrace(ex)
Dim i As Integer
For i = 0 To stackTrace.FrameCount - 1
  Dim stackFrame = stackTrace.GetFrame(i)
  Dim method = stackFrame.GetMethod()
  If (method.DeclaringType.Assembly = Assembly.GetExecutingAssembly()) Then
    ' Found the method - do something and exit the loop
    Exit For
  End If
Next i
Martin Liversage
  • 104,481
  • 22
  • 209
  • 256
  • 1
    If you change the declaration of stackFrame to Dim stackFrame As System.Diagnostics.Stackframe then you can obtain stackFrame.GetFileLineNumber(), but this may return 0. – Martin Jul 28 '14 at 10:21
1

e.ToString() will return the full details including a stack trace. The stack trace includes all the method names.

Steven Doggart
  • 43,358
  • 8
  • 68
  • 105
  • Wow it has been a long day don't know why I didn't realise that. However, that is just the general exception string, I want the methodinfo or single method name. Is there anyway for me to get the types out as objects or the calling assembly which I can then manipulate with reflection/ – LukeHennerley Sep 04 '12 at 13:45
  • I believe, e.TargetSite will get you what you are looking for. – Steven Doggart Sep 04 '12 at 13:49
  • +1 for making me realise that - but a little example to what I want is in the handler have a MethodInfo variable (Dim info as MethodInfo) and then set that to the Method which caused the exception (MethodA). Then the assembly/types if it is possible. – LukeHennerley Sep 04 '12 at 13:50
  • Just tried e.TargetSite and it gives me the level below the class method - File.ReadAllLines() so obviously this is the method which caused the exception not the method in the class which caused the exception (looking for the parent of target site if you will). Thanks again for the answer :) – LukeHennerley Sep 04 '12 at 13:52
  • 2
    @LukeHennerley: Your code will not always be only one level above the method where the exception was thrown. There may be multiple stack frames between your code and the code that threw the exception, or if it is your own code that threw the exception there are no stack frames in between. – Martin Liversage Sep 04 '12 at 13:55
  • I understand now - If I have MethodA which calls MethodB and in turn MethodC (MethodC throws the exception) the trace will not be able to get back to MethodA only the method within MethodC that caused the exception? Will getting the assembly of where the targetsite is held also be out of the question? – LukeHennerley Sep 04 '12 at 14:02
  • I've never used it, but it looks like `e.TargetSite.DeclaringType` returns the `System.Type` object for the type that contains the method. So, from there, `e.TargetSite.DeclaringType.Assembly` should get you the assembly, etc. – Steven Doggart Sep 04 '12 at 14:22
0

[Edited]

have a look at How to format Exception's stack trace in C#?. Use the constructor of System.Diagnostics.StackTrace that takes an exception.

Community
  • 1
  • 1
akton
  • 14,148
  • 3
  • 43
  • 47
  • I should have been more specific. You construct the System.Diagnostics.StackTrace object and pass the exception to the constructor. I will edit my answer. – akton Sep 04 '12 at 13:54