Crash handling in Silverlight (Part Two)

This post is the second part of a two part series.

Adding a little polish

In part one of this series we learned about the basic out-of-the-box crash handling that a new Silverlight project provides for both in- and out-of-browser applications, we learned how we can catch unhandled exceptions inside our application or let them escape into the browser to be handled by JavaScript (or a bit of both) and we learned that we are at the mercy of the HTML bridge.

What we had was far from fancy; the user would end up with a potentially broken Silverlight application or a blank screen and only some cryptic text in the JavaScript console to explain. This is not how we make friends, but now that we have a foundation, we can look at how to enhance the experience for our quality departments, ourselves and the poor souls that must suffer for our mistakes, our users. However, some simple modifications to our error handler can move the cryptic text out of the console into the page. We can even add some pizzazz and remove most of the cryptic text too. So let's take what we were left with at the end of part one and add a little polish.

In the following example, I've constructed a simple page that gives the user some information and provides a mailto link for sending the details to our QA department. When a crash occurs, the Silverlight application is hidden and the error page is displayed, customized to the specific error code1 and information.

function onSilverlightError(sender, args) {
    var errorType = args.ErrorType;
    var iErrorCode = args.ErrorCode;

    var emailMessage = "Dear Support,%0A%0A" +
        "Your application crashed.%0A%0A" +
        "Honestly, I only:%0A" +
        " ADD SOME DETAIL OF WHAT HAPPENED HERE%0A%0A" +
        "If you could fix this, that would be super awesome.%0A%0A" +
        "Thanks,%0A" +
        "A Very Important User%0A%0A~~~~~~~~%0A%0A";

    if (sender != null && sender != 0) {
        emailMessage += "Source: " + sender.getHost().Source + "%0A";
    }
    emailMessage += "Code: " + iErrorCode + "%0A";
    emailMessage += "Category: " + errorType + "%0A";
    emailMessage += "Message: " + args.ErrorMessage + "%0A";

    if (errorType == "ParserError") {
        emailMessage += "File: " + args.xamlFile + "%0A";
        emailMessage += "Line: " + args.lineNumber + "%0A";
        emailMessage += "Position: " + args.charPosition + "%0A";
    }
    else if (errorType == "RuntimeError") {
        if (args.lineNumber != 0) {
            emailMessage += "Line: " + args.lineNumber + "%0A";
            emailMessage += "Position: " + args.charPosition + "%0A";
        }
        emailMessage += "Method Name: " + args.methodName + "%0A";
    }

    var errorScreen = "<h1>Hello World!</h1>"
        + "<p>Sorry, but our application appears to have left the building.</p>"
        + "<p>Please <a href=\"mailto:quality@example.com\?subject=Incident Report&body="
        + emailMessage
        + "\">click here</a> and send us an e-mail.</p>";
    document.getElementById("silverlightControlHost").style.display = "none";
    var errorDiv = document.getElementById("errorLocation");
    errorDiv.innerHTML = errorScreen;
    errorDiv.style.display = "block";
}

Now, I understand, this is not the most elegant JavaScript in the world, but it works. Here is what your user sees…

Example of what a user will see when the application crashes
Example of what a user will see when the application crashes

…and if the user clicks our mailto link, they'll get something like this…

Example of the auto-generated e-mail incident report
Example of the auto-generated e-mail incident report

The example could be expanded to add additional information such as the URL of the application, the version of Silverlight and the user agent string by just modifying the JavaScript to include that information2. You could even show the same information on the HTML page that you include in the e-mail (in fact, you can go even further than that, just use your imagination…or read on for some suggestions). And yes, a little CSS would help, but I never promised it would be pretty—pretty can come later; I'm aiming for functional and as functional goes for showing that something is non-functional, this is good enough.

A bridge too far

Of course, as we have access to all the wonders of HTML and JavaScript, we could do so much more. For example, we could play a video to entertain the user while we call a web service that sends our error report automatically to our servers and tweets an apology (it's the personal touches that count). However, it doesn't matter how fancy and special we make the crash experience, it is all for nought once the user installs and uses our application out-of-browser or the HTML bridge is disabled. So, what do we do?

Out of the browser and into the app

The simplest way I have found to handle crash reporting in an out-of-browser application (or an application that lacks the HTML bridge) is to throw up a ChildWindow containing the details of the crash and provide no discernible means to dismiss it, thus disabling your application from further use without closing the application. This relies on the Silverlight runtime remaining intact even though your application suffered a problem; however, from my experience, crashes that take out the runtime are rare, especially in applications that have been tested and have well-formed, correct XAML.

Of course, if the runtime is still working, why stop at a ChildWindow? If you have access to the Silverlight runtime, you could do more like call a web service call or use some trusted API3 or COM4 interface. Whatever you try, exercise caution as you don't want your crash handling to crash as well. Keep it simple and it will serve you well.

Conclusions

Whichever route you choose, you should work hard to cater for all the scenarios that might be encountered, that way you will provide the support your user deserves. When deciding on your crash reporting strategy, always consider:

  • What level of network connectivity might be available?
  • Will the application be in- or out-of-browser? Do you support both?
  • Will the application be trusted and therefore have access to COM or Windows APIs?5
  • What Silverlight runtime(s) will you want to support?
  1. If you were paying attention there, you may have noticed that I mentioned the error code. There are many error codes that can be reported by Silverlight. You can use the error code to tailor your report or even consider not reporting a crash at all, but that depends on just how badly your application will react to the error. []
  2. Getting the User Agent string or the site URL are relatively simple, especially when compared with retrieving the Silverlight runtime version from within JavaScript. Thankfully, this was solved already, just visit this blog for details. []
  3. Silveright 5 []
  4. Silverlight 4 and up []
  5. Starting in Silverlight 5, both in- and out-of-browser trusted applications are supported. Earlier versions only support trusted applications when out-of-browser. []