Exception Shielding for JSON WCF Services
The DAL in mfLY! provides a very cool remote provider which allows you to execute saves and selects across the wire to a server repository. Actually, you aren’t even limited to querying/saving to a server database as the server side code also supports the same provider model effectively allowing you create either a store and forward integration layer or a real time pass through to some other system or anything else you might dream up and plug into the provider model.
The remote provider talks to the server over WCF JSON web services which gives us some very nice performance benefits on the devices. Once of the issues we’ve always had was the inability to use any of the Ent Lib Exception Shielding and instead ended up having our own try catch around all service methods in order to log errors and return proper information to the client. So to fix this, I’ve extended WCF to allow exception shielding behavior similar to Ent Libs and added the ability to return faults to the client serialized as json (instead of soap xml). This is very much a first pass, but I thought it would be interesting to share.
First of all, we need to create our own IErrorHandler:
public class JsonExceptionShieldingErrorHandler : IErrorHandler
{
private readonly string exceptionPolicyName;
public JsonExceptionShieldingErrorHandler()
: this(“WCF Exception Shielding”)
{
}
public JsonExceptionShieldingErrorHandler(string exceptionPolicyName)
{
this.exceptionPolicyName = exceptionPolicyName;
}
public string ExceptionPolicyName
{
get { return exceptionPolicyName; }
}
public bool HandleError(Exception error)
{
return true;
}
public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
try
{
ExceptionPolicy.HandleException(error, exceptionPolicyName);
if (!exceptionPolicyName.Equals(“WCF Exception Shielding”, StringComparison.InvariantCultureIgnoreCase))
{
ExceptionPolicy.HandleException(error, “WCF Exception Shielding”);
}
ProcessUnhandledException(error, ref fault, version);
}
catch (FaultContractWrapperException exception)
{
HandleFault(exception, ref fault, version);
}
catch (FaultException)
{
}
catch (Exception exception2)
{
ProcessUnhandledException(error, exception2, ref fault, version);
}
}
private static void HandleFault(
FaultContractWrapperException faultContractWrapper,
ref Message fault,
MessageVersion version)
{
try
{
fault = Message.CreateMessage(version, “”, faultContractWrapper.FaultContract, new DataContractJsonSerializer(faultContractWrapper.FaultContract.GetType()));
var wbf = new WebBodyFormatMessageProperty(WebContentFormat.Json);
fault.Properties.Add(WebBodyFormatMessageProperty.Name, wbf);
var rmp = new HttpResponseMessageProperty
{
StatusCode = HttpStatusCode.BadRequest,
StatusDescription = faultContractWrapper.Message
};
fault.Properties.Add(HttpResponseMessageProperty.Name, rmp);
}
catch (Exception unhandledException)
{
// There was an error during MessageFault build process, so treat it as an Unhandled Exception
// log the exception and send an unhandled server exception
Guid handlingInstanceId = ExceptionUtility.LogServerException(unhandledException);
HandleFault(unhandledException, ref fault, handlingInstanceId, version);
}
}
private static void HandleFault(
Exception error,
ref Message fault,
Guid handlingInstanceId,
MessageVersion version)
{
var reason = ExceptionUtility.FormatExceptionMessage(Resources.ClientUnhandledExceptionMessage, ExceptionUtility.GetHandlingInstanceId(error, handlingInstanceId));
fault = Message.CreateMessage(version, “”, reason, new DataContractJsonSerializer(typeof(string)));
var wbf = new WebBodyFormatMessageProperty(WebContentFormat.Json);
fault.Properties.Add(WebBodyFormatMessageProperty.Name, wbf);
var rmp = new HttpResponseMessageProperty
{
StatusCode = HttpStatusCode.InternalServerError,
StatusDescription = reason
};
fault.Properties.Add(HttpResponseMessageProperty.Name, rmp);
}
private static bool IsFaultException(Exception exception)
{
return typeof(FaultException).IsInstanceOfType(exception);
}
private static void ProcessUnhandledException(Exception originalException, ref Message fault, MessageVersion version)
{
ProcessUnhandledException(originalException, originalException, ref fault, version);
}
private static void ProcessUnhandledException(Exception originalException, Exception unhandledException,
ref Message fault, MessageVersion version)
{
if (!IsFaultException(unhandledException))
{
Guid handlingInstanceId =
ExceptionUtility.GetHandlingInstanceId(
unhandledException, Guid.Empty);
if (handlingInstanceId.Equals(Guid.Empty))
{
handlingInstanceId =
ExceptionUtility.LogServerException(
unhandledException);
}
HandleFault(unhandledException, ref fault, handlingInstanceId, version);
}
}
}
Notice that I’m hard coding this error handler to use “WCF Exception Shielding” as the name of the exception handling block (when you get into your config file).
Next we create a custom WebHttpBehavior which is pretty quick and easy:
public class JsonExceptionShieldingBehavior : WebHttpBehavior
{
protected override void AddServerErrorHandlers(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
endpointDispatcher.ChannelDispatcher.ErrorHandlers.Clear();
endpointDispatcher.ChannelDispatcher.ErrorHandlers.Add(new JsonExceptionShieldingErrorHandler());
}
}
Finally we have to add a factory to our service to load this custom behavior. I started trying to do this using attributes, but didn’t seem to be able to get into the WCF stack in the right place to actually return JSON. Create your factory:
public class CustomHostFactory : WebServiceHostFactory
{
public override ServiceHostBase CreateServiceHost(string constructorString, Uri[] baseAddresses)
{
var sh = new ServiceHost(typeof (EntityJsonService), baseAddresses);
sh.Description.Endpoints[0].Behaviors.Add(new JsonExceptionShieldingBehavior());
return sh;
}
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
return base.CreateServiceHost(serviceType, baseAddresses);
}
}
In your .svc add a reference to that factory that you just created:
<%@ ServiceHost Language=”C#” Debug=”true” Service=”BlueDot.Eam.Inventory.Integration.Services.EntityJsonService” Factory=”BlueDot.Eam.Inventory.Services.CustomHostFactory” %>
And that’s it!

Hi Tim,
Excellent post.
I’ve been trying to implement this, however in an AJAX-enabled WCF service this fails because the JsonErrorHandler also tries to handle the resulting fault and fails. Since this post is 2 years old I was wondering if you have any insights on this matter.
Thanks,
Dor.
Dor Rotman
July 24, 2011 at 8:06 am
It has indeed been a long time since I’ve look at this, but…. Is there a built in JsonErrorHandler for the AJAX-enabled WCF stuff? You probably need to make sure there is a single one that you control. I can’t promise anything, but if you can post a link to some code or maybe the exception you are getting I’ll see if anything jumps out at me.
Tim Clem
July 24, 2011 at 9:11 am
Hey Tim, thanks for quick response
The JsonErrorHandler has its own ProvideFault(error, version, ref fault) method, in which it checks whether fault is null or not.
In the simple case where there I don’t build the custom IErrorHandler, and I use exception shielding, then the exception is a FaultContractWrapperException since I use Exception Handling Application Block to convert the exception to a fault. The JsonErrorHandler disregards any data members I have set on the fault.
In the more complex case I build an IErrorHandler, the JsonErrorHandler will run after it and take the “ref fault” input it got and try to read it as SOAP. The fault parameter is populated with my IErrorHandler’s result. This fails on the reading since the message was prepared for JSON and not SOAP…
FirstName
The length of the value must fall within the range “1″ (Inclusive) – “20″ (Inclusive).
Parameter validation failed. Parameter name: customer
false
Thanks!
Dor Rotman
July 24, 2011 at 9:36 am
It seems WordPress doesn’t like XML. I replace the greater-than / less-than with [, ] accordingly.
This is the fault.ToString() result:
[root type="object]
[errors type="array"]
[item type="object"]
[Key]FirstName[/Key]
[Value]The length of the value must fall within the range “1″ (Inclusive) – “20″ (Inclusive).[/Value]
[/item]
[/errors]
[msg]Parameter validation failed. Parameter name: customer[/msg]
[success type="boolean"]false[/success]
[/root]
Thanks
Dor Rotman
July 24, 2011 at 9:40 am
Ok. I think what you are going to have to do is get down to a single error handler. When you create your custom ServiceHost like this:
var sh = new ServiceHost(typeof (EntityJsonService), baseAddresses);
sh.Description.Endpoints[0].Behaviors.Add(new JsonExceptionShieldingBehavior());
I think you might want to see what the other behaviors are on that endpoint and remove the default ones so you don’t get the collision. The other place to look would be here:
endpointDispatcher.ChannelDispatcher.ErrorHandlers.Clear();
endpointDispatcher.ChannelDispatcher.ErrorHandlers.Add(new JsonExceptionShieldingErrorHandler());
If you are following the code example above, you’ve already cleared out any existing which should do the trick. Without spending more time with this, I don’t know exactly where the built in JsonErrorHandler is getting added in.
Hope that help!
Tim Clem
July 24, 2011 at 10:16 am
Hey Tim,
When the Clear() call is executed in my implementation, the ErrorHandlers collection is empty.
I will try see how I can run it last in line so it will clear out the MS JsonErrorHandler.
Thanks!
Dor.
Dor Rotman
July 25, 2011 at 7:22 am