Condividi tramite


Error Handling

Microsoft Silverlight will reach end of support after October 2021. Learn more.

The Silverlight managed API has a managed layer of error handling and exception handling that wraps the runtime that processes your application code. In order to handle exceptions that originate from your application's user code, you can register a handler for UnhandledException. Platform code exceptions, as well as exceptions that you choose not to handle with UnhandledException, are passed on to the native/unmanaged error mechanism in the Silverlight plug-in. At this level, you can process the errors using the OnError handler that is specified during plug-in instantiation. Some errors and exceptions prevent further coding or scripting to Silverlight; others are considered less serious and allow you to continue coding or scripting to the application. This topic explains error handling concepts and the APIs and techniques that are relevant to general error and exception handling in Silverlight.

This topic contains the following sections.

  • Exceptions, Errors and the Silverlight Architecture
  • Managed API Error Handling
  • JavaScript API Error Handling
  • Related Topics

Exceptions, Errors and the Silverlight Architecture

In terms of the architecture, Silverlight is a runtime that executes your application code. Much of the Silverlight runtime is implemented internally as native code. This architecture exists for three primary reasons:

  • The Silverlight runtime is based on a core that also supports a browser host scripting model (the original model available for Silverlight 1.0 era applications)

  • The runtime must itself implement the base CLR engine/runtime from native code, particularly for Silverlight on Macintosh

  • XAML parsing in Silverlight is done partially through native code implementation

The managed API in Silverlight is thus often either a thin wrapper around a Silverlight core native function, or is managed code that is based on the initial CLR runtime and library specifically for Silverlight.

Managed APIs in Silverlight can raise exceptions. Often the exceptions that a given API raises as the primary exception of that specific class are documented in the .NET Framework Class Library for Silverlight reference topics. If they are wrappers, managed API actions can also result in an error at the native level. Sometimes, a native error is represented by a UnhandledException from the wrapper. However, it is also possible that the error occurs without an exception being raised, and in some of these cases the Silverlight runtime will shut down.

For more information, see Silverlight Architecture.

Managed API Error Handling

Generally speaking, managed code deals with exceptions rather than errors. However, Silverlight uses a native core as discussed previously in the "Exceptions, Errors and the Silverlight Architecture" section, and the remainder of this topic uses the term "error" when specifically referring to an error condition as reported by native code. Also, the Silverlight run time makes a distinction between platform-originated exceptions and application code-originated exceptions.

If you are new to managed programming and want more information about how exceptions work, see Handling and Throwing Exceptions.

Exceptions often include information as part of the exception's Message property value. This information is really only intended for use during the development of an application. The exact string reported as the Message can vary, and should not be relied upon in the actual deployed application behavior. In particular, the debug versions of Silverlight libraries typically contain additional information in the message, that would not be visible on a standard end-user runtime executing the same Silverlight application. The fixed portion of an exception message are often included as resources in the library, and referenced by the runtime exception when thrown. Other portions of exception messages can be passed by context, including by specific property values of exception classes.

Platform Exceptions and Application Exceptions

The Silverlight error/exception system makes a distinction between platform exceptions (exceptions that are relevant to the APIs that Silverlight implements for its own.NET library and core run time), and exceptions that are the result of executing an application's code in the core run time. Platform exceptions should be rare, but if they happen, they generally bring down the Silverlight core, and are never recoverable.

Handling managed exceptions from application code involves using the Application as a central handling point for any exception that originates from an application call. You write a single UnhandledException handler for your entire application.

Within an UnhandledException handler, the most interesting piece of information is usually the ExceptionObject. This property reports the specific exception that occured, and parallels the exception that would be reported to a debugger if a debugger were attached. You can call GetType() on the exception object, and use the type to switch to different code paths depending on the exception that occured. This technique is useful for isolating exceptions that your application might be able to recover from in a production run-time scenario, as is discussed in an upcoming section of this topic.

You can still write specific try/catch blocks as a technique for breaking exception handling into smaller modules, and for catching specific exceptions from specific calls. Specific try/catch is sometimes the best technique for certain exception handling scenarios, because you have better context available for how to correct for the exception. If there is a specific try/catch in your application code that catches an exception, Application.UnhandledException is not invoked. However, if an application try/catch leaves a specific exception uncaught, then Application.UnhandledException is invoked.

Exceptions During the Development Process

During the period that you are developing your application, developing in Visual Studio enables you to break into Silverlight exceptions at first chance. This is possible even if that exception is nonrecoverable and necessarily brings down the Silverlight core process or unloads the application domain.

For exceptions that originate from XAML parsing, which are usually nonrecoverable for purposes of a functioning application, you can break into the resulting XamlParseException. Line information in the event data can help you pinpoint the specific markup elements or attributes that failed to parse. Note that the nature of XAML parsing for Silverlight reports only the first parse issue encountered, so fixing the initial error may then lead to the next parse attempt surfacing other errors that are lexically forward in the same XAML file.

One particular area that does not always enable first chance exception breaks in Visual Studio is the initialization of the Silverlight plug-in, using the object tag or other techniques. These types of errors are in the domain of the host (typically a browser host) and may not necessarily be exposed with a service that Visual Studio can access and use for first chance breaks.

The default Visual Studio project templates for Silverlight generate a default UnhandledExceptionEventHandler implementation, within the file app.xaml.cs or app.xaml.vb. This particular UnhandledException handler is useful during the development phase, because managed exceptions can be surfaced in the browser host without stopping the application. This is accomplished by marking the exception handled and using the browser DOM to show the exception as a message box. You can thus display exception information on platforms and hosts that do not otherwise have Visual Studio available for debugging. You should not deploy applications with this handler as-is. Instead, your deploy-ready UnhandledException handler should log exceptions as you see fit, and only handle exceptions that can be recovered from, as is explained in the next section.

Layout Exceptions at Design Time

Certain layout exceptions in Silverlight have special design-time handling in the design tools, so that the tools can provide appropriate guidance for how to correct the problem without the Silverlight run-time shutting down within the design surface. Examples of these types of layout problems include Measure passes that return an infinite desiredSize, layout cycles, or template expansion by the designer that results in an invalid visual tree. Make sure to correct any such problems in the design and development phases. If these same problems still occur in production code and while not in a design mode, the exceptions are often not recoverable.

Recoverable and Nonrecoverable Exceptions

Part of the determination of what constitutes a recoverable exception for your application is controlled by how you write your UnhandledException handler. If you determine that a particular exception is recoverable and you do not need to process that exception further, your handler should set Handled in the event data to true. Recovering from the exception might mean entering a different code path, displaying a different UI, saving application-specific state to isolated storage so that the state can be used for a subsequent application restart, or other possibilities that are specific to your application scenario.

If you do not set Handled in the event data to true, then the exception might fall through to the unmanaged level of error handling. This can potentially be processed with an onError handler that you write in script, executed in the browser script host. However, if an exception reaches this point, the application's AppDomain is terminated, and managed application code can no longer execute.

NoteNote:

In some cases, such as certain interoperation or initial deployment scenarios, enabling errors to fall through to onError script handling might actually be desirable. But in the majority of cases you should mark any recoverable error as handled in the UnhandledException handler.

For more information, see UnhandledException, and "Unhandled Exception Processing" in Application Services.

Service Exceptions

During the development phase, debugging Silverlight services often requires techniques such as checking the transport-level information to and from the test client, and reconfiguring the service and service requests to use test domains rather than production domains. It is often helpful to enable server exceptions. For more information, see Debugging Services for Silverlight Applications.

Once a Silverlight application is deployed, any application that attempts to access a service should behave gracefully in cases where the service is unavailable or is not able to deliver a valid response. Clients should also gracefully handle cases where client access policy in place on a server denies access to the service.

If you are targeting Silverlight 4 or later, you can use the WCF SOAP fault programming model to handle declared faults on the client for production purpose, or undeclared faults for debugging purposes. Using the WCF SOAP fault programming model requires that you either configure the service to deliver faults with 200-series status codes, or that you register an alternative client HTTP stack for service communication. For more information, see Creating and Handling Faults in Silverlight.

Data Validation Errors and Exceptions

In some cases, properties where you are using run-time data validation also raise exceptions prior to the validation code executing, if you are running the application in a debugging environment. In Visual Studio, you can change exception-handling behavior by using the Debug menu, choosing Exceptions, and changing the behavior for some or all of the CLR exceptions. For more information on how data validation relates to exceptions, see Data Binding.

Background Threads

Any exceptions that occur on a background thread running in Silverlight are not promoted to UnhandledException.

XAML Parsing Errors

Ordinarily, XAML parser errors should not be in the domain of an error that you would potentially handle with UnhandledException handling in a deployed application. Any such XAML parser errors should have been detected during the development phase of your application. For more information, see Debugging Silverlight XAML.

However, one possible way that a parser error can be introduced at run time is if you use XamlReader.Load to read XAML at run time, and the string source for loading as XAML is constructed using string parsing, XML fragments, isolated storage, database records, or other sources that are harder to completely test as complete XAML sources. Another possible cause is if you are referencing types that are backed by an assembly that is not from the Silverlight core set of assemblies, and you have not packaged that assembly as part of your Silverlight deployment. Thus the assembly will be missing at run-time from the client perspective, and a XAML parser error can be how the missing-assembly issue is manifested.

NoteNote:

You should not permit users or other entities to supply arbitrary strings that are used as XamlReader.Load input. This is not just to avoid errors; loading arbitrary and unverified XAML can also have major security implications for your applications. See "Security Concerns with Creating Objects from XAML" section in Using XamlReader.Load.

Asynchronous Method Events

The UnhandledException technique does not capture exceptions that originate from asynchronous operations, such as download requests that fail. These exceptions are typically handled by dedicated handlers on the object that invokes the original asynchronous operation. Even if there is no dedicated handler attached, UnhandledException handlers are not invoked for these cases.

For example, if you are populating an image source with a URI, and anticipating the possibility for a load failure for that URI/image is an intentional part of your application design, you would typically provide a handler for ImageFailed that is attached to that specific Image object. If you have no handler, and the image fails to load, the runtime UI layout for that image will display as blank (potentially at 0x0 size if you did not specify height or width sizing). The application can otherwise function, and the UnhandledException event is not raised to the application.

JavaScript API Error Handling

You can provide error-handling support in your Silverlight-based scripting applications at the JavaScript level in a number of ways, depending on the type of the error. The OnError handler on the Silverlight plug-in can be used to handle parser errors, run-time errors, and other types of errors. A try/catch block can be placed around a synchronous method call, and errors resulting from the call can be handled in the catch block. Event handlers can be attached to asynchronous error events, such as MediaFailed. If you use Visual Studio with script debugging enabled, you can use the integrated JavaScript debugging support to set breakpoints and inspect values.

NoteNote:

Specific error messages are not covered in the Silverlight documentation. For more information, see Silverlight Plug-in Error Messages.

Defining an OnError Event Handler

You can define an error handler for your Silverlight-based application by setting the OnError parameter of the Silverlight plug-in object element to a custom event-handler function.

The onError handler takes two parameters: the sender object and the event data. sender is the object on which the error occurred; this is always the plug-in instance, and does not report specific objects in the object tree. The second parameter is an instance of the ErrorEventArgs object or one of its derived objects, ParserErrorEventArgs or RuntimeErrorEventArgs. Because JavaScript is prototype-based, you could first determine the errorType that is available for all these errors, and then query a property of a specific type of error event data based on knowing which eventargs matches that errorType.

The following table lists the properties on an ErrorEventArgs object. These properties are common to all error events handled by onError.

Property

Description

errorMessage

The message that is associated with the error event.

errorType

The type of error, defined as a value of the ErrorType enumeration.

errorCode

The numeric code associated with the error event.

The following table lists the properties that are specific to parser errors, which are defined on a ParserErrorEventArgs object.

Property

Description

charPosition

The character position in which the error occurred.

lineNumber

The line on which the error occurred.

xamlFile

The XAML file in which the error occurred.

xmlAttribute

Do not use.

xmlElement

Do not use.

The following table lists properties that are specific to run-time errors, which are defined on a RuntimeErrorEventArgs object.

Property

Description

charPosition

The character position in which the error occurred.

lineNumber

The line on which the error occurred.

methodName

The method that is associated with the error.

The following example shows how to set the OnError event handler to a user-defined function named OnErrorEventHandler as part of an object tag declaration for a Silverlight-based application in a browser host.

<object data="data:application/x-silverlight-2," type="application/x-silverlight-2" ...>
  <param name="source" value="silverlightapplication1.xap"/>
  <param name="onerror" value="OnErrorEventHandler"/>
...
</object>

The following JavaScript example shows the associated event-handler function for the OnError event of the Silverlight plug-in. The ErrorType property on the ErrorEventArgs is checked to determine the specific type of error. If the error is a run-time or parser error, additional error information is added to the display message.

function OnErrorEventHandler(sender, errorArgs)
{
    // The error message to display.
    var errorMsg = "Silverlight Error: \n\n";
    
    // Error information common to all errors.
    errorMsg += "Error Type:    " + errorArgs.errorType + "\n";
    errorMsg += "Error Message: " + errorArgs.errorMessage + "\n";
    errorMsg += "Error Code:    " + errorArgs.errorCode + "\n";
    
    // Determine the type of error and add specific error information.
    switch(errorArgs.errorType)
    {
        case "RuntimeError":
            // Display properties specific to RuntimeErrorEventArgs.
            if (errorArgs.lineNumber != 0)
            {
                errorMsg += "Line: " + errorArgs.lineNumber + "\n";
                errorMsg += "Position: " +  errorArgs.charPosition + "\n";
            }
            errorMsg += "MethodName: " + errorArgs.methodName + "\n";
            break;
        case "ParserError":
            // Display properties specific to ParserErrorEventArgs.
            errorMsg += "Xaml File:      " + errorArgs.xamlFile      + "\n";
            errorMsg += "Xml Element:    " + errorArgs.xmlElement    + "\n";
            errorMsg += "Xml Attribute:  " + errorArgs.xmlAttribute  + "\n";
            errorMsg += "Line:           " + errorArgs.lineNumber    + "\n";
            errorMsg += "Position:       " + errorArgs.charPosition  + "\n";
            break;
        default:
            break;
    }
    // Display the error message.
    alert(errorMsg);
}

Using the Silverlight.js OnError Event Handler

Silverlight.js is a utility library of script functions that can instantiate a Silverlight plug-in in HTML by forming the necessary object tagging. The Silverlight.js technique for instantiation provides a default event handler for the OnError handler parameter. When you leave the onError parameter in a CreateObject call unspecified or null (using the Silverlight.js functions), the default handler function defined in Silverlight.js is invoked when native script errors are encountered. For more information on how to include the Silverlight.js file and call its specific functions, see How to: Add Silverlight to a Web Page by Using JavaScript.

Important noteImportant Note:

The default OnError event-handler function defined in Silverlight.js displays a dialog box for many errors. You probably do not want to deploy production code or Web sites with this behavior. OnError is used and will be invoked for many asynchronous errors that cannot be fully eliminated from a real-time, real-world deployment of a Silverlight-based application.

Synchronous Method Calls and try/catch Blocks in JavaScript

Synchronous method calls block the calling function until the call returns. A try/catch statement enables you to test a block of JavaScript code for errors. The try block contains the code to be run, and the catch block contains the code to be executed if an error occurs.

If a synchronous method call fails and the method call is in a try/catch block, an error object, described in "ECMAScript Language Specification" (ECMA-262), is passed to the catch block and an onError event is not raised. Because an onError event is not raised, the onError event handler is not called. If a synchronous method call fails and the method call is not inside a try/catch block, an onError event is raised and routed to the onError handler of the Silverlight plug-in. The ErrorType in the event arguments sent to the onError handler is set to RuntimeError.

The only Silverlight-specific error information returned to the catch block through the error object is the ErrorMessage and, on Internet Explorer only, the ErrorCode. The message property on the error object is set to the error message.

The try/catch functionality is currently supported on all browsers and operating systems that Silverlight supports except for Apple Safari and Macintosh. Because of this limitation, we recommend using onError for all synchronous run-time methods.

Silverlight Asynchronous Error Events in JavaScript

An asynchronous call returns control immediately after it has been called. An error that occurs during the asynchronous call raises an error event that is specific to the type of call. If a handler is not attached to the specific asynchronous event, the onError handler is invoked. An example of an asynchronous error event is the MediaFailed event.

The following example shows how to attach an event handler to the MediaFailed event.

  <MediaElement x:Name="MediaPlayer" MediaFailed="MediaFailedHandler" />

The following example shows an event handler for the MediaFailed event.

function MediaFailedHandler(sender, args)
{

    // Create basic error message.
    var errorMsg = "\n Media Error Message     \n" ;

    // Add Media information.
    errorMsg += "MediaElement Name: " + sender.Name + "\n";
    errorMsg += "Media File Name: " + sender.Source + "\n";

    // Display error information.
    alert(errorMsg);  
}

Enabling JavaScript Debugging in Visual Studio

When you create a Silverlight-based application in Visual Studio, you can use Visual Studio to debug your JavaScript code. You can set breakpoints, view and modify variable values, and run script in the Immediate window. To enable JavaScript debugging in Visual Studio, you might need to clear the "Disable script debugging" settings in Internet Explorer. By default, the check boxes for these settings are selected. After you clear the "Disable script debugging" settings, you can set breakpoints in your JavaScript code.

NoteNote:

If you are running Windows Vista or Windows 7, you must run Visual Studio with administrator access; otherwise, breakpoints will be ignored.