Exception Management in SharePoint

Correct exception handling is an essential part of reliable and maintainable SharePoint applications. In general, exception handling for a SharePoint application is not very different from any other .NET Framework application. The general guidelines in the .NET Framework Design Guidelines chapter Design Guidelines for Exceptions also apply to SharePoint applications.

This section gives general exception handling guidelines and also specific guidance for handling exceptions in SharePoint contexts, such as Web Parts, list item event receivers, and workflow execution. The Partner Portal Reference Implementation demonstrates how to implement some of these techniques.

General Exception Handling Guidelines

This section describes the following guidelines:

  • Catch only exceptions that you handle.
  • Catch the most specific type of exception.
  • Avoid empty catch blocks.
  • Implement a handler for unexpected exceptions.

Catch Only Exceptions That You Handle

In general, you should catch only exceptions that you handle. Handling an exception includes one or more of the following actions:

  • Take an alternative action to compensate for the exception. In some cases, the exception is a correctable error. For example, if you try to call a Web service and it is too busy to handle the request, you could handle the "service to busy" exception by retrying the invocation a few more times.
  • Log or trace the exception information. It is sometimes useful to record exception information for later use. For example, if you encounter an unexpected exception, you should log the exception information and let the process fail gracefully. However, if it is not an unexpected exception, and your code can compensate for the exception, it is often helpful for debugging purposes to write the exception information to the trace log.
  • Show an error message. In some cases, exceptions indicate problems that require action by the end user. For unknown or unexpected exceptions, you should display a generic error message that explains that there is an unknown problem. If you know what problem the exception indicates, you can catch that specific exception type and show an error message that clearly explains the situation to the user.
  • Add additional information to the exception or increase the level of abstraction of the exception. An exception that is not caught will propagate up the call stack. Methods at a higher level in the call stack may have more information about the task being performed. For example, lower-level methods in a configuration manager might throw a KeyNotFoundException if a configuration key could not be found. Within the higher-level methods, this exception information could then be wrapped within a ConfigurationSettingNotFoundException instance.

Catch the Most Specific Type of Exception

Always try to catch the most specific type of exception. Do not catch the general Exception type. Failure to follow this guideline can result in unexpected behavior in your code and hard-to-find bugs.

// Do not catch the general type exception:
// bool isValid;
// try
// {
//int.parse(inputValue);
//isValid = true;
// }
// catch(Exception)
// {
//isValid = false;
// }

// Instead, catch a specific exception: FormatException.
bool isValid;
try
{
int.parse(inputValue);
isValid = true;
}
catch(FormatException)
{
isValid = false;
}

Note

There is one exception to this recommendation: implementing an unhandled exception handler, which is described later in this topic.

Avoid Empty Catch Blocks

You should avoid catching an exception with an empty catch block.

// Try to avoid this construct:
// int convertedValue = 0;
// try
// {
//    convertedValue = (int) myValue;
// }
// catch (InvalidCastException)
// {
//    // Do nothing if the cast fails. 
// }

// Instead, use this construct.
int convertedValue = 0;
if (myValue is int)
{
    convertedValue = (int) myValue; 
}

Never catch the general Exception type with an empty catch block. This can result in bugs that are very hard to find. For example, consider a try/catch block around a statement that catches the top-level Exception type. While executing the statement, another thread wants to abort the current thread. A ThreadAborted exception will be raised. However, the catch block will intercept the ThreadAborted exception and handle it. This prevents the thread from being aborted.

// Never do this:
// try
// {
//    // operation that can potentially fail
// }
// catch(Exception)
// {
//   // Do nothing (hide the exception). // }

Implement a Handler for Unexpected Exceptions

It is not possible to predict all exceptions that can occur with a system. Therefore, you must sometimes implement handlers at system boundaries for otherwise unhandled exceptions.

The following illustration shows an example of this.

Example of system and exception boundaries

Ff647598.430f0db0-c3ba-4bb6-826c-b74d3cebd1ba(en-us,PandP.10).png

For example, consider a Web page that contains several Web Parts. Suppose that the Web Parts invoke methods of a repository that eventually calls into an external Web service. In this scenario, there are several locations where an unhandled exception handler is appropriate:

  • Page. In a SharePoint application, if an unhandled exception is not caught, it propagates to the page that was requested by the end user. SharePoint has a built-in global exception handler that will catch any unhandled exceptions and redirect the user to an appropriate error page. Although it is hard to implement a custom global exception handling policy for SharePoint, it is possible to handle unhandled exceptions in custom pages by responding to the Page_Error event provided by ASP.NET. The error page should not display any unhandled exception details to the end user because this can pose a security risk.
  • Web service. Within the Web service, you should catch all unhandled exceptions, log them and return a general exception message. This is also called exception shielding. For more information, see Exception Shielding on MSDN. A Web service should also not expose any unhandled exception information.
  • Web Part. By default, if an unhandled exception occurs within a Web Part, the exception propagates to the Web page and triggers the unhandled exception handler of the page. This is not always the desired behavior. For example, it is possible in SharePoint to give end users the option of composing their own pages using Web Parts. When a Web Part throws an exception, it is difficult for the user to remove that Web Part from the page. To avoid this problem, you can implement an unhandled exception handler in this location.

Logging or Tracing Exceptions

Unhandled exceptions should be logged so that system administrators know when a component is not performing as expected. You should augment the log message with additional information that is helpful to the system administrator. The following code shows how to log an exception with additional information for the system administrator. This code uses the logging component of the SharePoint Guidance Library.

catch(Exception unhandledException)
{
    ILogger logger = SharePointServiceLocator.Current.GetInstance<ILogger>();
    logger.LogToOperations(unhandledException, “Could not connect to the database”);
}

In some situations, you should also write exception information to the application's trace log. Trace logs are intended for developers who need to analyze application failures. The following code shows how to write exception information to a trace log using the SharePoint Guidance Library.

int retryCount = 0;
while (retryCount < 3)
{
    try
    {
       // Call into a service.
       break; // exit while loop
    }
    catch(ServiceBusyException exception)
    { 
        retryCount++;
        ILogger logger = SharePointServiceLocator.Current.GetInstance<ILogger>();
        logger.TraceToDeveloper(exception, “Service was busy. Attempt “ + 
                                                                       retryCount);

        if (retryCount == 3)
            throw;
    }
}

This code tries to execute a Web service. If it succeeds within three tries, no exception is propagated to the caller of this code. However, if the developer needs to find out why the application is slow, it can be useful to know that the application needed to retry Web service invocations.

Handling Exceptions in Web Parts

Normally, unhandled exceptions that occur within a Web Part propagate to the Web page and are resolved by the unhandled exception handler of the page. The handler redirects the user to an error page that contains an informative error message.

As a result, an unhandled exception in a single Web Part can prevent the Web page as a whole from being displayed. This behavior is sometimes desired because an unhandled exception can potentially corrupt data on the page. In other situations, it can be better to catch unhandled exceptions within Web Parts. With this approach, an unhandled exception results in an appropriate error message being displayed by the Web Part that received the exception. All other Web Parts on the page will continue to function normally.

Note

Unfortunately, because of the way the ASP.NET controls are implemented, it is not possible to create a single unhandled exception handler that catches all unhandled exceptions that might occur during the lifetime of a control or its child controls. For this reason, the Partner Portal application implements its unhandled exception handler in the presenter layer. This allows the application to catch most "logic"-related errors.

The Partner Portal Reference implementation demonstrates how to create Web Parts that implement unhandled exception handlers. These handlers log errors and let the user interface display a friendly error message. The goal is to do the following:

  • Catch the exception.
  • Log the exception to the event log and the trace log.
  • Replace the entire user interface (UI) of the Web Part with an informative error message.

The following illustration shows the implementation of this kind of Web Part in the Partner Portal application. The Web Part implements the Model View Presenter (MVP) pattern. For more information, see The Model-View-Presenter (MVP) Pattern.

Web Parts that implement unhandled exception handlers

Ff647598.36dd6410-4e11-4373-b585-f2d8f048ea15(en-us,PandP.10).png

This diagram consists of the following parts:

  • The Web Part. The Web Part itself is only the host for the view and the presenter objects. The Web Part should contain as little code as possible. Therefore, the chances of anything failing in the code of the Web Part are low.
  • The view. The view is a user control that displays the UI of the Web Part. To make the view as simple as possible, it is designed only to handle positive code paths. It has the ability to display functional errors, such as validation errors, but it does not contain logic for displaying unhandled exceptions. The view is added directly to the control tree. The view is a child control of the ErrorVisualizer control. Unhandled exceptions are intercepted by the ErrorVisualizer, and the ErrorVisualizer can suppress the UI if an error has occurred.
  • The presenter. The presenter contains the logic of the Web Part. This is the best location to implement an unhandled exception handler. However, when an unhandled exception occurs, it needs a mechanism for displaying the friendly error message. The view does not have this functionality, so the presenter calls the ErrorVisualizer to display errors. Because the steps to handle an unhandled exception are usually the same (log and display an error message), this behavior is encapsulated in the ViewExceptionHandler class.
  • The ErrorVisualizer control. The ErrorVisualizer control makes it easier to display technical errors and hide the view. This control has an interface that allows consumers to set an error message on it. When an error message is set, it will display that error message and hide any child controls that might be present. The view is added as a child control of the ErrorVisualizer; when an error message is set, the view will no longer be displayed.
  • The ViewExceptionHandler class. The code that would go in the unhandled exception handler is often the same for each Web Part. To maximize code reuse this code is factored into a ViewExceptionHandler class.

Web Parts with unhandled exception handlers occur in several places in the Partner Portal application. The following code comes from the Product Details Web Part. It shows how to create the ErrorVisualizer control and how to add the view (ProductDetailsControl class) to the ErrorVisualizer.

protected override void CreateChildControls()
{
   base.CreateChildControls();

   // Create a control that will display any errors that might 
   // occur in the ProductDetailsControl.
   ErrorVisualizer errorVisualizer = new ErrorVisualizer();

   this.Controls.Add(errorVisualizer);
   // Add the ProductDetailsControl to the host. This way, if an error has to be   
   // rendered, the host can prevent the ProductDetailsControl from being displayed. 
   this.productDetailsControl = (ProductDetailsControl)Page.LoadControl(
                           "~/_controltemplates/Contoso/ProductDetailsControl.ascx");
   this.productDetailsControl.ErrorVisualizer = errorVisualizer;
   errorVisualizer.Controls.Add(this.productDetailsControl); 
   this.productDetailsControl.LoadProduct(this.productSku);
}
  • The following code from the Product Details Presenter shows how the unhandled exception handler was implemented. The call to the HandleViewException method logs the error and uses the ErrorVisualizer control to display an informative error message to the user.
public void LoadProduct(string sku)
{
   try
   {
      /// ...
   }
   catch(Exception ex)
   {
      // If something goes wrong, make sure the error gets logged
      // and a non-technical message is displayed to the user.
      new ViewExceptionHandler().HandleViewException(ex,  
             this.ErrorVisualizer,              Contoso.PartnerPortal.ProductCatalog.Properties.Resources.ProductDetailsErrorMessage);
   }
}

Handling Exceptions in List Item Event Receivers

SharePoint allows you to attach an event receiver object to a list. A list item event receiver is an instance of a class that derives from the SPItemEventReceiver class. Methods of the list item event receiver are invoked when an item in the list is added, removed, or modified.

If an unhandled exception occurs during the execution of a list item event receiver method, you should perform the following actions:

  • Log the exception.
  • Set the Cancel property of the SPItemEventProperties object passed as an argument to true. This cancels the action.

If an unhandled exception occurs while executing a method of a list item event receiver, the action is not canceled by SharePoint, by default. Failing to cancel the action can cause corruption of list data. For example, consider the situation of validation code in the list item event receiver. If the validation fails with an unhandled exception, the list item's pending changes should not be made. Allowing the changes can be a security risk. Also, invalid data can be very hard to remove after it is added to the list.

Note

There are some situations where it is not appropriate to set the Cancel property to true.

The following code from Partner Portal application's IncidentTaskReceiver class shows how to implement an unhandled exception handler for a list item event receiver:

public override void ItemAdding(SPItemEventProperties properties)
{
   try
   {             
      incidentManagementRepository.WriteToHistory(
                     string.Format(CultureInfo.CurrentCulture, TaskCreatedMessage,   
                                   properties.AfterProperties[TitleField]));
   }
   catch (Exception ex)
   {
      ListExceptionHandler handler = new ListExceptionHandler();
      handler.HandleListItemEventException(ex, properties, 
                                        Resources.HandleListItemEventExceptionValue);
   }
}

ListExceptionHandler is a helper class declared in the Partner Portal application's Contoso.Common project. Calling the HandleListItemEventReceiver method of this class logs the exception to the EventLog and cancels the event. There are overloads of the available for this method if you do not want to cancel the event.

The ListExceptionHandler class includes logic that handles exceptions that occur during exception handling itself.

Handling Exceptions During Workflow Execution

In custom workflow code, you should follow the standard guidelines for handling exceptions with the try/catch pattern. Windows Workflow Foundation provides using the FaultHandlerActivity activity as an additional way to catch exceptions thrown by workflow activities.

The SharePoint Guidance Library's subsite creation workflow demonstrates how to wrap a LogToHistoryListActivity activity in a FaultHandlerActivity activity. The fault handler activity handles any exceptions of type SubSiteCreationException and logs a message to the workflow history list associated with the workflow.

The following illustration shows the fault handler for the subsite creation workflow.

Fault handler for subsite creation workflow

Ff647598.6cd17d93-5edf-427b-91a4-d02c57c10887(en-us,PandP.10).png

The following illustration shows how the FaultHandlerActivity object is configured using the FaultType property to catch exceptions of a specified type.

FaultHandlerActivity configuration

Ff647598.79ebbb3d-110a-4e2e-8c85-2d598a407672(en-us,PandP.10).png

For more information about handling exceptions in Windows Workflow, see Windows Workflow Tutorial: Introduction to Fault Handling on MSDN.

Home page on MSDN | Community site