How to: Configure Support for Unhandled Exceptions

Retired Content

The Web Service Software Factory is now maintained by the community and can be found on the Service Factory site.

This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies.
This page may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist.

Retired: November 2011

By default, WCF services do not return information from unhandled exceptions to protect sensitive data. Exception data contains low-level information about the implementation of a service that can be used by attackers to compromise a Web service. During development, it is often necessary to view this information to troubleshoot issues with the service. As a result, WCF provides the ability to configure a service to return information from unhandled exceptions.

The process of configuring the service for unhandled exceptions can be done by directly modifying the configuration file, using the Service Configuration Editor that comes with the Microsoft .NET Framework 3.5 Software Development Kit (SDK), or by using WCF Service Factory recipes. The specific configuration element involved is named serviceDebug; it contains an attribute named includeExceptionDetailInFaults that can be used to determine whether unhandled exception information can be returned. It is also important to note that this configuration setting is only valid for unhandled exceptions; it has no affect on planned exceptions thrown using the FaultException type.

There are several things to keep in mind when configuring support for unhandled exceptions:

A Web service should never be deployed into production with includeExceptionDetailInFaults set to true.

All exceptions in a service implementation should be caught and handled. In other words, you should implement services with the goal of never allowing unhandled exceptions to be returned from a service request.

Use of this configuration setting is not recommended unless absolutely necessary in a development environment only.

This configuration setting has no affect over the use of a FaultException that can be thrown from a WCF service.

Using the Service Configuration Editor

The service configuration editor that comes with the Microsoft .NET Framework 3.5 Software Development Kit (SDK) can also be used to configure a service for unhandled exceptions. This process requires you to open the host configuration file in the service configuration editor and then add or update configuration data for service behaviors.

Prerequisites

This task requires the following:

  • A WCF service Visual Studio project must be already created.
  • The Microsoft Windows SDK for .NET Framework 3.5 must be installed.

Process

This process assumes that you have created a WCF service using the Web Service Software Factory.

To configure unhandled exceptions using the Service Configuration Editor

In the Service Configuration Editor, open the Web.config file used by the WCF service host project.

Expand Advanced, right-click Service Behaviors, and then click New Service Behavior Configuration.

In the Configuration tree view, select the new behavior that was created in step 2, type a name for the behavior in the Name box, and then click Add.

In the Adding Behavior Element Extension Sections dialog box, click serviceDebug, and then click Add.

Expand the behavior added in step 2, select the serviceDebug extension that was added in step 4, enter the following, and then click Add:

General:

  • IncludeExceptionDetailInFaults: True

Expand Services, select the service being configured, and then enter the following:

General:

  • BehaviorConfiguration: [Name from step 3]

On the File menu, click Save to update the configuration file.

On the File menu, click Exit to end the current edit session.

Outcome

By using the Service Configuration Editor, an attribute named includeExceptionDetailInFaults is set to true in the serviceDebug element of a service behavior configuration. The following configuration example shows a service behavior configured to include exception details.

<serviceBehaviors>
   <behavior name="EmployeeManager_Behavior">
      <serviceDebug includeExceptionDetailInFaults="true"/>
      <serviceMetadata httpGetEnabled="true" />
   </behavior>
</serviceBehaviors>

When this attribute is set to true and an unhandled exception is thrown in the service, a SOAP fault similar to the following is returned.

<s:Envelope xmlns:s="https://schemas.xmlsoap.org/soap/envelope/">
  <s:Body>
    <s:Fault>
      <faultcode mlns:a="https://schemas.microsoft.com/net/2005/12/wcf/dispatcher">
        a:InternalServiceFault
      </faultcode>
      <faultstring xml:lang="en-US">
          Exception in FindEmployeeByLastName
      </faultstring>
      <detail>
        <ExceptionDetail xmlns="http:// org/2004/07/System.ServiceModel"         
                         xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
          <HelpLink i:nil="true"/>
          <InnerException i:nil="true"/>
          <Message>Exception in FindEmployeeByLastName</Message>
          <StackTrace> at EmployeeService.ServiceImplementation.EmployeeManager. FindEmployeeByLastName( String request) in C:\Dev\EmployeeSvcManual\Source\Service\EmployeeService.ServiceImplementation\EmployeeManager.cs:line 25&#xD;
   at SyncInvokeFindEmployeeByLastName(Object , Object[] , Object[] )&#xD;
   at System.ServiceModel.Dispatcher.InvokeDelegate.Invoke(Object target, Object[] inputs, Object[] outputs)&#xD;
   at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]&amp; outputs)&#xD;
   at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin( MessageRpc&amp; rpc)&#xD;
   at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5( MessageRpc&amp; rpc)&#xD;
   at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage4( MessageRpc&amp; rpc)&#xD;
   at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage3( MessageRpc&amp; rpc)&#xD;
   at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage2( MessageRpc&amp; rpc)&#xD;
   at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage1( MessageRpc&amp; rpc)&#xD;
   at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)
          </StackTrace>
          <Type>System.ApplicationException</Type>
        </ExceptionDetail>
       </detail>
    </s:Fault>
  </s:Body>
</s:Envelope>

As mentioned earlier, this SOAP fault contains sensitive information that describes exactly where the exception occurred in the WCF service.

When the includeExceptionDetailInFaults is set to false, the following SOAP fault is returned for the same exception shown in the previous example.

<s:Envelope xmlns:s="https://schemas.xmlsoap.org/soap/envelope/">
  <s:Body>
    <s:Fault>
      <faultcode mlns:a="https://schemas.microsoft.com/net/2005/12/wcf/dispatcher">
        a:InternalServiceFault
      </faultcode>
      <faultstring xml:lang="en-US">
        The server was unable to process the request due to an internal error.  For more information about the error, either turn on IncludeExceptionDetailInFaults (either from ServiceBehaviorAttribute or from the &lt;serviceDebug&gt; configuration behavior) on the server in order to send the exception information back to the client, or turn on tracing as per the Microsoft .NET Framework 3.5 SDK documentation and inspect the server trace logs.
      </faultstring>
    </s:Fault>
  </s:Body>
</s:Envelope>

As you can see in this example, a generic message is returned in the SOAP fault that tells the client application that the server was unable to process the request because of an internal error.

To catch unhandled exceptions in a client application, WCF provides an object named FaultException that can be used by WCF client applications. The following code example shows how a client application can catch unhandled exceptions and display information returned by the fault exception.

catch (FaultException ex)
{
    string msg = "FaultException: " + ex.Message;
    MessageFault fault = ex.CreateMessageFault();
    if (fault.HasDetail == true)
    {
        System.Xml.XmlReader reader = fault.GetReaderAtDetailContents();
        if (reader.Name == "ExceptionDetail")
        {
            ExceptionDetail detail = fault.GetDetail<ExceptionDetail>();
            msg += "\n\nStack Trace: " + detail.StackTrace;
        }
    }
    MessageBox.Show(msg);
}

As shown in the previous code example, a FaultException can be used to catch exceptions that are thrown by a WCF service. The FaultException type contains a method named CreateMessageFault that can be used to extract detail information from the fault if it was included in the service message. In other words, if the WCF service is configured to return exception details by setting includeExceptionDetailInFaults to true, the MessageFault.HasDetail property is also true. After you know that exception details exist, you can use a generic method named GetDetail<T> to convert the fault message into an ExceptionDetail type.

It is important to note that the ExceptionDetail type is returned only when the service is configured to include exception detail in faults and unhandled exceptions are returned. You can also return .NET Framework managed exceptions using a FaultException type, which is why the name for detail contents should be checked before executing the GetDetail<T> method. The MessageFault method named GetReaderAtDetailContents returns an XmlReader that identifies the detail type using a Name property.