Architecting WCF for Error and Condition Validation

As an architect I am often tasked with understanding how to build operations into a framework so that other developers can focus on the task at hand rather than reconstructing/rebuilding a foundation each time they carry out an action.  This is an essential task in any software system, in particular a large one.  I have seen too often that teams do not want to address these fundamental needs that every system has and end up getting bitten due to lack of vision.  Addressing the role of the code architect for a team is the topic for another post, this one is about handling errors and business logic, and doing so in a very centralized way.

So what is the problem?

The question has always been, how do we efficiently and agnostically get errors back from a web service?  To take that one step further, how do we communicate errors to the caller in a way that is both efficient and understandable regardless of the platform.  I recently had to battle this problem in a WCF REST Service I am writing for a client.  This is a hugely important component of a system, so I thought it made sense to make it available to all:

Your Result

I am not a big fan of error codes, I feel that if you have a large system you can quickly find yourself lost with so many different codes.  With that in mind, I decided to use enumerations for error codes now:

    public enum ResultCode
    {
        Success = 0x0000,
        PlanetaryAlignmentBad = 0x0001,
        NotAuthorized = 0x0002
    }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Using this enumeration, I want to define a base class for all of my results.  I don’t know if this approach has a formal pattern, but it was something that a colleague of mine, Chad, proposed to me.  This allows a kind of view model approach with what is being returned to the caller, here is ResultBase:

    [DataContract]
    public abstract class ResultBase
    {
        [DataMember]
        public bool IsSuccess
        {
            get { return ResultCode == ResultCode.Success; }
            private set { }
        }

        [DataMember]
        public string ErrorMessage { get; set; }

        [DataMember]
        public ResultCode ResultCode { get; set; }
    }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

What I am defining here is a very simple base class that our two classes, SuccessfulResult and FailedResult.  The idea is that, for our example, well return one of these two classes.  In your application you could have a class like UserAuthenticateResult and have it return the necessary information pertaining to the operation.

Inspectors

One of the nice things about WCF is the insane number of extensibility points, you can change just about everything regarding the way the system works.  For our example, we will first define a class the allows us to inspect the outgoing result of a service call:

    public class OutboundResultParameterInspector : IParameterInspector
    {
        #region Implementation of IParameterInspector

        public object BeforeCall(string operationName, object[] inputs)
        {
            return null;
        }

        public void AfterCall(string operationName, object[] outputs,
                               object returnValue, object correlationState)
        {
            var result = returnValue as ResultBase;
            if (result != null)
            {
                if (!result.IsSuccess)
                {
                    // handle the error
                    throw new OperationException(
                           result.ErrorMessage, result.ResultCode);
                }
            }
        }

        #endregion
    }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

A quick note: the value returned by BeforeCall will be passed as the correlationState to the AfterCall method.

All this code is doing is taking the result of our operation and attempt to cast it to an object of type ResultBase, this will be successful IF the object being returned inherits from ResultBase.  If this isn’t the case, then the operation simply goes on as normal.

Where this really gets interesting is if the operation fails.  In this code we throw an exception.  The reason for this is simple: we need to invoke the global error handler for WCF so we can rewrite the return message.  You see, REST is about relying on what already exists, and that means for errors, using standard HTTP error codes.  Doing this allows the caller to better handle whatever problem occurs and keeps with the true spirit of REST.

But before we can talk about error handling, we have to get WCF to actually invoke this inspector.  That can be done a few ways, for our example we will use an attribute.

    public class InspectOutgoingResultAttribute : Attribute, IOperationBehavior
    {
        #region Implementation of IOperationBehavior

        public void Validate(OperationDescription operationDescription)
        {
            
        }

        public void ApplyDispatchBehavior(OperationDescription operationDescription,
            DispatchOperation dispatchOperation)
        {
            dispatchOperation.ParameterInspectors.Add(
                new OutboundResultParameterInspector());
        }

        public void ApplyClientBehavior(OperationDescription operationDescription,
            ClientOperation clientOperation)
        {
            
        }

        public void AddBindingParameters(OperationDescription operationDescription, 
            BindingParameterCollection bindingParameters)
        {
            
        }

        #endregion
    }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

The only thing this class is doing is modifying the Dispatcher to add the appropriate inspector.  With this applied, ANY operation that this decorates is subjected to our inspector, for example:

        [InspectOutgoingResult]
        public SuccessfulResult GetSuccessfulResult()
        {
            return new SuccessfulResult();
        }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Simple.  With this in place, we can selectively decorate the methods and this will allow us to handle any business logic cases with grace.

You probably noticed that I was throwing an OperationException above if the result failed.  This is a custom class that I have created.  It has two purposes: 1) determine the appropriate HTTP Status code that will represent the error being thrown and 2) invoke the error handling of WCF so we can rewrite the message.  Well talk about this portion next.

Lets Rewrite History

One of the things that I love in statically typed languages like C# is the ability to define a particular type being returned by a method, it adds a certain degree of structure the code.  One of things I hate about statically typed languages is that I have to define a type for the return.

With respect to the tenants of REST its important to use what HTTP provides to return a result, as is done by Twitter, TripIt, Facebook, Foursquare, etc.  Doing this makes things cleaner and relieves us from using special conditions and/or logic for error handling.  We will do this for our example, but first we have to define a global error handler to override the default.  We do this by implementing IErrorHandler:

    public class CustomErrorHandler : IErrorHandler
    {
        public bool HandleError(Exception error)
        {
            return true;
        }

        public void ProvideFault(Exception error, MessageVersion version,
                      ref Message fault)
        {
            var ex = (OperationException) error;
            fault = Message.CreateMessage(version, string.Empty,
                      new ErrorMessage(ex.OutcomeCode, ex.Message)
                , new DataContractJsonSerializer(typeof(ErrorMessage)));

            var wbf = new WebBodyFormatMessageProperty(WebContentFormat.Json);
            fault.Properties.Add(WebBodyFormatMessageProperty.Name, wbf);

            var response = WebOperationContext.Current.OutgoingResponse;
            response.ContentType = "application/json";
            response.StatusCode = ex.StatusCode;
        }
    }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

The essence of what we are doing here is, if we encounter an error we intercept the response being transmitted (this is not your return result) and re-serialize it using our ErrorMessage class (below):

    [DataContract]
    public class ErrorMessage
    {
        [DataMember]
        public ResultCode ResultCode { get; private set; }

        [DataMember]
        public string Message { get; private set; }

        public ErrorMessage(ResultCode code, string message)
        {
            ResultCode = code;
            Message = message;
        }
    }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

This class only allows us a template for serializing the error state into JSON form (notice that this code sample relies upon the response format to be JSON, this will not work, without modification, with XML or other transport formats).

With this in place we just have to make sure that WCF is aware of our error handler.  It is also important to understand that error handling is done at the ServiceContract level.  So when we create our attribute, it can only work if applied at the class level.  Here is our attribute:

    [AttributeUsage(AttributeTargets.Class)]
    public class HandleErrorsAttribute : Attribute, IServiceBehavior
    {
        // non implemted method omitted
       
        public void ApplyDispatchBehavior(ServiceDescription description,
                 ServiceHostBase hostBase)
        {
            hostBase.ChannelDispatchers.Cast().ToList().ForEach(
                      (d) => d.ErrorHandlers.Add(new CustomErrorHandler()));
        }
    }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

I had tinkered with seeing if I could put the error handler on individual operations, but that doesn’t appear to be supported through IOperationBehavior.

Once this is in place, you can play with the service and watch as things are being caught.  Here is the sample code I used while proving the idea:

    // some attributes ommitted for brevity
    // dont forget to disable automatic automaticFormatSelectionEnabled
    // in the web.config
    [ServiceContract]
    [HandleErrors]
    public class Service1
    {
        [WebGet(UriTemplate = "/Success", ResponseFormat=WebMessageFormat.Json)]
        [InspectOutgoingResult]
        public SuccessfulResult GetSuccessfulResult()
        {
            return new SuccessfulResult();
        }

        [WebGet(UriTemplate = "/Fail", ResponseFormat=WebMessageFormat.Json)]
        [InspectOutgoingResult]
        public FailedResult GetFailedResult()
        {
            return new FailedResult();
        }
    }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Simplistic I admit, but it proved the point.  If I call /Fail then I see my response totally rewritten with the error message and the appropriate Http Status code.  If I call /Success then things work as they should.

Closing

REST with WCF can be done by hand as it requires only minor config changes and some setup in the Global.asax file, however, I recommend searching “rest” in your online templates, you will find a ready to use template prepared for you. It works out of the box and is easy to modify to fit your desires.

REST is a very useful methodology for designing services because it forces you to thing agnostically so you are not forced to care who is accessing your service and from what platform.  However, it is equally important to be diligent when selecting your REST API structure.  I always tell people I talk with that the URLs should almost speak when they are being called.  The idea of REST is to make the URL look more like an English sentence.  It should express what you are doing.  “I am GETting a Load”, “I am POSTing an Update”, “I am PUTting a new entry in the database”.  Use the various verbs to help make the API more understandable. It will go a long way to helping others understand your service and code

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s