10

You are apparently able to rethrow an Exception without discarding the stack trace in .NET.

However it doesn't appear to be working.

Basic usage I'm following is thus:

    [WebMethod]
    public void ExceptionTest()
    {
        try
        {
            throw new Exception("An Error Happened");
        }
        catch (Exception ex)
        {
            evlWebServiceLog.WriteEntry(ex.ToString(), EventLogEntryType.Error);
            throw;
        }
    }

Problem is, the line number in the exception in the line of the throw; line, not the original throw new line.

I've tested it in a simple exe project and without the logging to the windows log line. It doesn't make any difference, the stack trace always has the wrong line number in it, making it less than useful.

Why is it doing this? How do I do it correctly?

RoboJ1M
  • 1,590
  • 2
  • 27
  • 34
  • That does not lose the stack trace. What makes you think that it does? Are you not logging or displaying `ex.ToString()`? – John Saunders Feb 06 '14 at 10:23
  • Is the line number in the ´CallStack` of the ´InnerException´ correct? – Jens H Feb 06 '14 at 10:24
  • Are you sure you are using `throw` and not `throw ex`? Also see http://stackoverflow.com/q/730250/11683 for inspiration. – GSerg Feb 06 '14 at 10:25
  • @ROBOJ, I do not agree with you, How about wrapping inner exception if you are so desperate? – dipak Feb 06 '14 at 10:25
  • 10
    apparently its a limitation - if a method has more than one throw you get the last line number - http://stackoverflow.com/questions/2493779/wrong-line-number-on-stack-trace – NDJ Feb 06 '14 at 10:26
  • 2
    Sorry, I muddled up "losing stack trace" with "wrong line number". This question was indeed answered here http://stackoverflow.com/questions/2493779/wrong-line-number-on-stack-trace – RoboJ1M Feb 06 '14 at 11:13

2 Answers2

6

You do not lose original exception if you place it in an inner exception.

[WebMethod]
public void ExceptionTest()
{
    try
    {
        throw new Exception("An Error Happened");
    }
    catch (Exception ex)
    {
        evlWebServiceLog.WriteEntry(ex.ToString(), EventLogEntryType.Error);
        throw new Exception("Your message", ex);
    }
}
Jason Beck
  • 1,061
  • 1
  • 12
  • 18
neodim
  • 468
  • 4
  • 15
  • 3
    But you loose original exception type (though in your example both original and rethrown exceptions are of Exception type). ExceptionDispatchInfo.Capture(ex).Throw() throws exception of original exception type. – wziska Oct 23 '15 at 11:27
6

I've used the following for years. Don't know if there a less "dodgy" way to achieve it in more up to date .Net frameworks though:

public void PreserveStackTrace(Exception ex)
{
    MethodInfo preserve = ex.GetType().GetMethod("InternalPreserveStackTrace",
                                                 BindingFlags.Instance | BindingFlags.NonPublic);
    preserve.Invoke(ex,null);
}

To use this:

[WebMethod]
public void ExceptionTest()
{
    try
    {
        throw new Exception("An Error Happened");
    }
    catch (Exception ex)
    {
        evlWebServiceLog.WriteEntry(ex.ToString(), EventLogEntryType.Error);
        PreserveStackTrace(ex);
        throw ex;
    }
}

Update: based on @dcastro's comment, I'd fancy an extension method in 4.5 (in < 4.5 it could still be an extension wrapping the method above):

public static void ReThrow(this Exception ex)
{
    var exInfo = ExceptionDispatchInfo.Capture(ex); 
    exInfo.Throw();
}

So you'd just have:

    catch (Exception ex)
    {
        evlWebServiceLog.WriteEntry(ex.ToString(), EventLogEntryType.Error);
        ex.ReThrow();
    }
Jon Egerton
  • 40,401
  • 11
  • 97
  • 129