In my last post I described a simple way to handle exceptions in WCF services (It might be helpful to read it before this one). Now I’d like to go a step further writing a solution to provide JSON exceptions. This approach is helpful for applications using pure JavaScript to connect to a WCF service. For me it makes a lot of sense to have a service that transparently provides JSON responses with exception information instead of regular HTML or XML responses, which are very difficult to deal with using JavaScript.
First we need to create our Error class. This error class will contain all the attributes we define for our JSON Exception. This class will be serialized as JSON before sending it as response when an exception occurs.
[DataContract]
public class AjaxError
{
[DataMember]
public int Code { get; set; }
[DataMember]
public String Message { get; set; }
}
Then we need to write our ErrorHandler class implementing IErrorHandler interface. In the ProvideFault method we will take care of the object serializing the response object and setting the response content type and status. You may notice that we are always setting the response status as BadRequest, this is just a personal decision, you can set it as InternalServerError o any other status you decide.
public class ErrorHandlerEx : IErrorHandler
{
public bool HandleError(Exception error)
{
return true;
}
public void ProvideFault(Exception exception, MessageVersion version, ref Message message)
{
AjaxError error = new AjaxError();
error.Code = 1;
error.Message = exception.Message;
message = Message.CreateMessage(version, "", error, new DataContractJsonSerializer(error.GetType()));
var wbf = new WebBodyFormatMessageProperty(WebContentFormat.Json);
message.Properties.Add(WebBodyFormatMessageProperty.Name, wbf);
WebOperationContext.Current.OutgoingResponse.ContentType = "application/json";
WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.InternalServerError;
}
}
After that we create a behavior inheriting from WebHttpBehavior and in the AddServerErrorHandlers class we remove the existing error handlers and add ours.
public class WebHttpBehaviorEx : WebHttpBehavior
{
protected override void AddServerErrorHandlers(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
endpointDispatcher.ChannelDispatcher.ErrorHandlers.Clear();
endpointDispatcher.ChannelDispatcher.ErrorHandlers.Add(new ErrorHandlerEx());
}
}
Now we need to write our own service factory inheriting from WebServiceHostFactory and in the CreateServiceHost method we add our custom behavior to the endpoint.
public class ServiceHostFactory : WebServiceHostFactory
{
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
ServiceHost host = new ServiceHost(typeof(Services), baseAddresses);
ServiceEndpoint endpoint = host.AddServiceEndpoint(typeof(IServices), new WebHttpBinding(), "");
endpoint.Behaviors.Add(new WebHttpBehaviorEx());
return host;
}
}
Finally we need to set our Service factory in the Factory attribute of the ServiceHost tag for our Service Markup.
<%@ ServiceHost
Language="C#"
Debug="true"
Service="Services"
CodeBehind="Services.svc.cs"
Factory="ServiceHostFactory"
%>