10101010101001

0101010101001

Posts Tagged ‘Stack Trace

Silverlight stack trace line numbers

with 8 comments

As you probably know, to have stack traces line numbers in a .net app you need pdb files.
In Silverlight though, pdb files don’t get included in the XAP. Even if it was possible to include them you probably wouldn’t want them there because they tend to be huge and you want to have a fast loading web-site.

So what will you do when your client calls you and says he received an error message like the one below?
NullReferenceException
at ChaptersView.ChaptersTree_OnMouseMove
at ChaptersView.GetPreviousCommandButton

After I had a look today at the answer to this question, it became obvious:

Step 1)
In the place you now log or show exceptions to the user, you stop writing a normal stack trace using exception.ToString() or exception.StackTrace.
You should write a stacktrace that includes IL offsets using the code below:

...
catch (Exception exception)
{
            string errorDescription = string.Empty;
            try
            {
                StackTrace st = new System.Diagnostics.StackTrace(ex);
                string stackTrace = "";

                if (st != null)
                {
                    foreach (StackFrame frame in st.GetFrames())
                    {
                        stackTrace = "at " + frame.GetMethod().Module.Name + "." + frame.GetMethod().ReflectedType.Name +
                                     "." + frame.GetMethod().Name + "  (IL offset: 0x" +
                                     frame.GetILOffset().ToString("x") + ")\n" + stackTrace;
                    }
                }
                errorDescription = stackTrace;
            } catch //sometimes there are no stackframes, just use ex.ToString() in those cases
            {
                errorDescription = ex.ToString();
            }
            //do something with error description, like show it to the user or send it to your log server  
}

If we pass the exception that generated the stacktrace in our first example, it will look like:

NullReferenceException
at ChaptersView.ChaptersTree_OnMouseMove (IL offset: 0x44)
at ChaptersView.GetPreviousCommandButton (IL offset: 0x28)

Step 2: Client sends you an exception/log that includes IL offsets
You can use Reflector or IL Disassembler (which comes with visual studio) to find out the piece of code that generated the exception.
I prefer IL Disassembler because Reflector will only show you IL code from those IL offsets, and there’s a large chance you don’t read IL as well as you read C#.

So you have to perform the following steps:
1) Go to start menu and start IL Disassembler
2) Inside IL Disassembler go to File->Open and load the dll (not the XAP) where the exception was thrown. (e.g. …\Release\Client.dll)
3) Go to View->Show source lines
4) Now navigate to the last method that appears in the stacktrace and we look after the IL offset from the stacktrace.
In our example above this is ChaptersView.GetPreviousCommandButton and has offset 0x28

Inside IL Disassembler we will see a mix of C# code and corresponding IL code:

  IL_001c:  brtrue.s   IL_0029
//000193:             {
//000194:                 throw new NullReferenceException(“Test Exception”);
  IL_001e:  ldstr      "Test Exception"
  IL_0023:  newobj     instance void [mscorlib]System.Exception::.ctor(string)
  IL_0028:  throw
//000195:             }
//000196:
//000197:             var previousCommandButton =
 

As you can see, at IL_0028 there’s the instruction that caused the exception.
This is IL code, but because we’ve checked “View->Show source lines” we also get the corresponding C# code just a few lines above.

//000193: {
//000194: throw new NullReferenceException();

So, in this case the exception was thrown because I’ve thrown it explicitly in order to show how IL offsets and IL Disassembler can be used to get an alternative to stack trace line numbers in silverlight.

Also please don’t just put that piece of code in every catch block. Create a method like “string GetStackTraceFromException(Exception ex)”
Another good idea would be to have some centralized error service, on the server side. You would then send those exception descriptions automatically along with method parameter values logged with PostSharp, whenever an error happens.
So by the time the client calls you, you have fixed the problem and he’s impressed ;)

Happy Debugging.

Advertisements

Written by Liviu Trifoi

April 21, 2011 at 6:15 pm