tags:

views:

2405

answers:

10

I am trying to add an unhandled exception handler in .net (c#) that should be as helpfull for the 'user' as possible. The end users are mostly programers so they just need a hint of what object are they manipulating wrong.

I'm developing a windows similar to the windows XP error report when an application crashes but that gives as much imediate information as possible imediatly about the exception thrown.

While the stack trace enables me (since I have the source code) to pinpoint the source of the problem, the users dont have it and so they are lost without further information. Needless to say I have to spend lots of time supporting the tool.

There are a few system exceptions like KeyNotFoundException thrown by the Dictionary collection that really bug me since they dont include in the message the key that wasnt found. I can fill my code with tons of try catch blocks but its rather agressive and is lots more code to maintain, not to mention a ton more of strings that have to end up being localized.

Finally the question: Is there any way to obtain (at runtime) the values of the arguments of each function in the call stack trace? That alone could resolve 90% of the support calls.

A: 

I'm not aware of anything like that, but have wanted it myself. I usually do it myself when throwing exceptions, but if it's not yours to throw, then you may be out with the rest of us.

Kilhoffer
+1  A: 

I don't believe there is a built-in mechanism. Retrieving each frame of the stack trace, while allowing you to determine the method in the trace, only gives you the reflected type information on that method. No parameter information. I think this is why some exceptions, notably, ArgumentException, et. al. provide a mechanism to specify the value of the argument involved in the exception since there's no easy way to get it.

Peter Meyer
+4  A: 

I don't think System.Diagnostics.StackFrame supplies argument information (other than the method signature).

You could instrument the troublesome calls with trace logging via AOP, or even use its exception interception features to conditionally log without having to litter your code. Have a look around http://www.postsharp.org/.

A: 

I don't know a way to obtain the values of the arguments of each function in the call stack trace, but one solution would be to catch the specific exception (KeyNotFoundException in your example) and re-throw it in a new Exception. That allows you associate any additional information you wish

For example:

Dim sKey as String = "some-key"
Dim sValue as String = String.Empty

Try
   sValue = Dictionary(sKey)
Catch KeyEx As KeyNotFoundException
   Throw New KeyNotFoundException("Class.Function() - Couldn't find [" & sKey & "]", KeyEx)
End Try

I appreciate your statement about localising the error strings, but if your audience are 'mostly programmers' then convention already dictates a comprehension of English to some degree (rightly or wrongly - but that's another debate!)

Andrew
Yes, I know I can, but that is exacly what Im trying to avoid. Last cound I made I have about 200+ calls to hashtables and they will increasse everyday. Im thinking of a helper function but it still looks ugly and only solves the KeyNotFoundException.
Caerbanog
Maybe a helper function is the way to go, sorry I couldn't help (added to my Favourites so I can check-back to see what you decide) :o)
Andrew
A: 

Since the end users are developers, you can provide them with a version that enables logging of all the key values/arguments that are passed. And provide a facility so that they can turn on/off logging.

Vivek
A: 

Once you have the exception the two things you are interested in are System.Diagnostics.StackTrace and System.Diagnostics.StackFrame

There is an MSDN example here

slf
+1  A: 

Unfortunately you can't get the actual values of parameters from the callstack except with debugging tools actually attached to the application. However by using the StackTrace and StackFrame objects in System.Diagnostics you can walk the call stack and read out all of the methods invoked and the parameter names and types. You would do this like:

System.Diagnostics.StackTrace callStack = new System.Diagnostics.StackTrace();
System.Diagnostics.StackFrame frame = null;
System.Reflection.MethodBase calledMethod = null;
System.Reflection.ParameterInfo [] passedParams = null;
for (int x = 0; x < callStack.FrameCount; x++)
{
    callStack.GetFrame(x);
    calledMethod = frame.GetMethod();
    passedParams = calledMethod.GetParameters();
    foreach (System.Reflection.ParameterInfo param in passedParams)
     System.Console.WriteLine(param.ToString()); 
}

If you need actual values then you're going to need to take minidumps and analyse them i'm afraid. Information on getting dump information can be found at:

http://www.debuginfo.com/tools/clrdump.html

Wolfwyrd
The problem with this is you're getting the stack from inside the Catch, not the stack at the time of the exception.
GeekyMonkey
A: 

it is theoretically possible to do what you want by taking advantage of the Portable Executable (PE) file format to get the variable types and offsets, but I ran into a [documentation] wall trying to do this a couple of years ago. Good luck!

Steven A. Lowe
A: 

If you could do what you are looking for, you would be defeating an integral part of .NET security.

The best option in the case, it to attach to a debugger or profiler (either of them can access those values). The former can be attached, the latter need to be active before the program starts.

leppie
A: 

Likewise, I've not found anything to derive the parameters automatically at runtime. Instead, I've used a Visual Studio add-in to generate code that explicitly packages up the parameters, like this:

public class ExceptionHandler
{
    public static bool HandleException(Exception ex, IList<Param> parameters)
    {
        /*
         * Log the exception
         * 
         * Return true to rethrow the original exception,
         * else false
         */
    }
}

public class Param
{
    public string Name { get; set; }
    public object Value { get; set; }
}

public class MyClass
{
    public void RenderSomeText(int lineNumber, string text, RenderingContext context)
    {
        try
        {
            /*
             * Do some work
             */
            throw new ApplicationException("Something bad happened");
        }
        catch (Exception ex)
        {
            if (ExceptionHandler.HandleException(
                    ex, 
                    new List<Param>
                    {
                        new Param { Name = "lineNumber", Value=lineNumber },
                        new Param { Name = "text", Value=text },
                        new Param { Name = "context", Value=context}
                    }))
            {
                throw;
            }
        }
    }
}

EDIT: or alternatively, by making the parameter to HandleException a params array:

public static bool HandleException(Exception ex, params Param[] parameters)
{
   ...
}

...
if (ExceptionHandler.HandleException(
                    ex, 
                    new Param { Name = "lineNumber", Value=lineNumber },
                    new Param { Name = "text", Value=text },
                    new Param { Name = "context", Value=context}
                    ))
{
    throw;
}
...

It's a bit of a pain generating the extra code to explicitly pass the parameters to the exception handler, but with the use of an add-in you can at least automate it.

A custom attribute can be used to annotate any parameters that you don't want the add-in to pass to the exception handler:

public UserToken RegisterUser( string userId, [NoLog] string password )
{
}

2ND EDIT:

Mind you, I'd completely forgotten about AVICode:

http://www.avicode.com/

They use call interception techniques to provide exactly this kind of information, so it must be possible.

Steve Morgan