Skip to content

WebErrorHandler Overview

mikeobrien edited this page Sep 14, 2010 · 2 revisions

The WcfRestContrib.ServiceModel.Web.WebErrorHandler provides the following functionality:

  1. It will automatically serialize error messages based on the request Accept header if the WcfRestContrib.ServiceModel.Description.WebDispatchFormatterAttribute attribute is applied to the invoked method (See more about this under De/serialization Overview). If it is not applied to the invoked method then the message is returned as html.
  2. If the thrown exception is of type WcfRestContrib.ServiceModel.Web.WebException the specified status will be set in the outgoing message and the friendly message will be passed. All other exceptions are considered unhandled and are passed as a 500 with a general error message.
  3. It will call the logging handler, if specified, and pass the exception and request details.

To use the WebErrorHandler you will need to use the WCF REST Contrib custom error handler behavior (See more about that under Custom Error Handler Overview). Specify the custom handler as the WebErrorHandler declaratively:

[ServiceConfiguration(true)]
[ErrorHandler(typeof(WcfRestContrib.ServiceModel.Web.WebErrorHandler))]
public class Books : IBooksService

Or in configuration as follows:

<system.serviceModel>
    <extensions>
        <behaviorExtensions>
            <add name="errorHandler" 
                 type="WcfRestContrib.ServiceModel.Configuration.ErrorHandler.BehaviorElement, WcfRestContrib, 
                       Version=x.x.x.x, Culture=neutral, PublicKeyToken=89183999a8dc93b5"/>
        </behaviorExtensions>
    </extensions>
    <serviceBehaviors>
        <behavior name="Rest">
            <errorHandler 
               errorHandlerType="WcfRestContrib.ServiceModel.Web.WebErrorHandler, WcfRestContrib"/>
        </behavior>
    </serviceBehaviors>
</system.serviceModel>

In your service you can throw a WebException to pass an http status and friendly error message to the client. For example if we are retrieving a book and it does not exists we would pass back a status of 404 and a friendly error message as follows:

public Book GetBook(string isbn)
{
    Domain.CatalogItem item = Domain.Catalog.GetItem(isbn);
    if (item == null)
        throw new WebException(System.Net.HttpStatusCode.NotFound,
            "Sorry, we dont have the book you're looking for.");
    else
        return new Book() {...};
}

In this example the WebErrorHandler will see that a WebException was thrown and automatically set the response http status and serialize and return the friendly message. As mentioned earlier it will be serialized based on the request Accept header if the WebDispatchFormatterAttribute is applied to the invoked method (See more about this under De/serialization Overview) otherwise it is returned as html. If the WebDispatchFormatterAttribute is being used the serialized response will be the following data contract:

[DataContract(Name="Error", Namespace="")]
private class WebExceptionContract
{
    ...
    [DataMember(Name = "Status")]
    public int Status { get; set; }

    [DataMember(Name = "Message")]
    public string Message { get; set; }
}

Also as noted earlier, a custom log handler can be specified. Log handlers must implement the WcfRestContrib.Diagnostics.IWebLogHandler interface and have a parameterless constructor. For example:

public class LogHandler : WcfRestContrib.Diagnostics.IWebLogHandler 
{
        public void Write(
            Exception exception, 
            Uri uri, 
            string method, 
            string contentType, 
            long contentLength, 
            string accept, 
            string userAgent, 
            System.Net.WebHeaderCollection headers)
        {
            if (!(exception is WebException))
                Debug.WriteLine(
                    string.Format("{0} - {1}: {2}",
                    method,
                    uri.ToString(),
                    exception.Message));
        }
}

You can specify the log handler by applying the WcfRestContrib.ServiceModel.Description.WebErrorHandlerConfigurationBehavior to a service declaratively:

[ServiceConfiguration(true)]
[ErrorHandler(typeof(WcfRestContrib.ServiceModel.Web.WebErrorHandler), "Please call support at 867-5309 for assistance.")]
[WebErrorHandlerConfiguration(typeof(Runtime.LogHandler))]
public class Books : IBooksService {...}

Or in configuration:

<system.serviceModel>
    <extensions>
        <behaviorExtensions>
            <add name="webErrorHandler" 
                 type="WcfRestContrib.ServiceModel.Configuration.WebErrorHandler.ConfigurationBehaviorElement, WcfRestContrib, 
                       Version=x.x.x.x, Culture=neutral, PublicKeyToken=89183999a8dc93b5"/>
        </behaviorExtensions>
    </extensions>
    <serviceBehaviors>
        <behavior name="Rest">
            <webErrorHandler logHandlerType="NielsBohrLibrary.Runtime.LogHandler, NielsBohrLibrary" 
                             unhandledErrorMessage="Please call support at 867-5309 for assistance."/>
            ...
        </behavior>
    </serviceBehaviors>
</system.serviceModel>

Exceptions that are not WebException’s are considered unhandled. You can specify a custom error message to display when an unhandled error occurs.

NOTE: The WcfRestContrib.ServiceModel.Web.WebServiceHost allows you to specify configuration based behaviors if you do not want to specify these declaratively. See more about it under Declarative Binding & Behavior Overview.