Friday, February 24, 2012

Custom Errors in WCF REST Services - Part I

Support for REST in WCF has improved enough to make it a viable option for those wanting to expose a RESTful API to their services. Error reporting in such an API is something that should be thought through from the beginning. How will users be notified when something doesn't work right? Getting a consistent data contract for error messages that originate from your application isn't all that hard with a little custom behaviors. However, getting the same data contracts respected by IIS and WCF itself can be a bit of a trick. If you don't take care of all 3 (application, WCF, and IIS) layers, then your REST API response would be difficult to parse. I'm sure your API consumers wouldn't appreciate this:

HTTP/1.1 405 Method Not Allowed
Allow: GET, PUT, DELETE, POST
Content-Type: text/html
Server: Microsoft-IIS/7.5
X-Powered-By: ASP.NET
Date: Wed, 11 Jan 2012 02:48:21 GMT
Content-Length: 1293

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"/>
<title>405 - HTTP verb used to access this page is not allowed.</title>
<style type="text/css">
<!--
body{margin:0;font-size:.7em;font-family:Verdana, Arial, Helvetica, sans-serif;background:#EEEEEE;}
fieldset{padding:0 15px 10px 15px;} 
h1{font-size:2.4em;margin:0;color:#FFF;}
h2{font-size:1.7em;margin:0;color:#CC0000;} 
h3{font-size:1.2em;margin:10px 0 0 0;color:#000000;} 
#header{width:96%;margin:0 0 0 0;padding:6px 2% 6px 2%;font-family:"trebuchet MS", Verdana, sans-serif;color:#FFF;
background-color:#555555;}
#content{margin:0 0 0 2%;position:relative;}
.content-container{background:#FFF;width:96%;margin-top:8px;padding:10px;position:relative;}
-->
</style>
</head>
<body>
<div id="header"><h1>Server Error</h1></div>
<div id="content">
 <div class="content-container"><fieldset>
  <h2>405 - HTTP verb used to access this page is not allowed.</h2>
  <h3>The page you are looking for cannot be displayed because an invalid method (HTTP verb) was used to attempt access.</h3>
 </fieldset></div>
</div>
</body>
</html>

Part I - Application Generated Errors
Part II - WCF Generated Errors
Part III - IIS Generated Errors

Application Generated Errors
Making sure all of your services conform to the same error data contract is not difficult. WCF comes out of the box with the IErrorHandler extension interface which allows you the opportunity to handle and translate any faults that occur on a service. IErrorHandler has two methods to implement and mapping any faults to a custom error data contract can be done here.

One approach that I've seen work well is to have all faults in your application inherit from a base Fault that has useful properties for your API consumers. You can then use the different fault classes to convey any exception that your application might throw.
[DataContract]
public class FaultBase
{
    public FaultBase(string message, string code)
    {
        this.Message = message;
        this.Code = code;
    }

    public string Message { get; set; }
    public string Code { get; set; }
}

[DataContract]
public class ItemNotFoundFault : FaultBase
{
    public ItemNotFoundFault()
        : base("The resource item was not found.", "ItemNotFound")
    { }
}

Any exception caught by your IErrorHandler implementation can be translated into one of your faults and sent back to the caller. Nothing special here. I'm not going into a lot of detail on this because there are plenty examples of this on the web.

In Part II, I'll discuss how to handle errors generated inside WCF that don't get handled by the IErrorHandler implementation.

No comments:

Post a Comment