Returning Error Details from AJAX-Enabled WCF Service Returning Error Details from AJAX-Enabled WCF Service ajax ajax

Returning Error Details from AJAX-Enabled WCF Service


EDIT: Updated the post with a proper custom json error handler

The quick but non-preffered way.

<serviceDebug includeExceptionDetailInFaults="true"/>

In Your service behavior will give you all the details you need.

The Nice way

All exceptions from the application are converted to an JsonError and serialized using a DataContractJsonSerializer. The Exception.Message is used directly. FaultExceptions provide the FaultCode and other exception are threated as unknown with faultcode -1.

FaultException are sent with HTTP status code 400 and other exceptions are HTTP code 500 - internal server error. This not nescessary as the faultcode can be used to decide if it is and unknown error. It was however convenient in my app.

The error handler

internal class CustomErrorHandler : IErrorHandler{    public bool HandleError(Exception error)    {        //Tell the system that we handle all errors here.        return true;    }    public void ProvideFault(Exception error, System.ServiceModel.Channels.MessageVersion version, ref System.ServiceModel.Channels.Message fault)    {        if (error is FaultException<int>)        {            FaultException<int> fe = (FaultException<int>)error;            //Detail for the returned value            int faultCode = fe.Detail;            string cause = fe.Message;            //The json serializable object            JsonError msErrObject = new JsonError { Message = cause, FaultCode = faultCode };            //The fault to be returned            fault = Message.CreateMessage(version, "", msErrObject, new DataContractJsonSerializer(msErrObject.GetType()));            // tell WCF to use JSON encoding rather than default XML            WebBodyFormatMessageProperty wbf = new WebBodyFormatMessageProperty(WebContentFormat.Json);            // Add the formatter to the fault            fault.Properties.Add(WebBodyFormatMessageProperty.Name, wbf);            //Modify response            HttpResponseMessageProperty rmp = new HttpResponseMessageProperty();            // return custom error code, 400.            rmp.StatusCode = System.Net.HttpStatusCode.BadRequest;            rmp.StatusDescription = "Bad request";            //Mark the jsonerror and json content            rmp.Headers[HttpResponseHeader.ContentType] = "application/json";            rmp.Headers["jsonerror"] = "true";            //Add to fault            fault.Properties.Add(HttpResponseMessageProperty.Name, rmp);        }        else        {            //Arbitraty error            JsonError msErrObject = new JsonError { Message = error.Message, FaultCode = -1};            // create a fault message containing our FaultContract object            fault = Message.CreateMessage(version, "", msErrObject, new DataContractJsonSerializer(msErrObject.GetType()));            // tell WCF to use JSON encoding rather than default XML            var wbf = new WebBodyFormatMessageProperty(WebContentFormat.Json);            fault.Properties.Add(WebBodyFormatMessageProperty.Name, wbf);            //Modify response            var rmp = new HttpResponseMessageProperty();            rmp.Headers[HttpResponseHeader.ContentType] = "application/json";            rmp.Headers["jsonerror"] = "true";            //Internal server error with exception mesasage as status.            rmp.StatusCode = System.Net.HttpStatusCode.InternalServerError;            rmp.StatusDescription = error.Message;            fault.Properties.Add(HttpResponseMessageProperty.Name, rmp);        }    }    #endregion}

Webbehaviour used to install the above error handler

internal class AddErrorHandlerBehavior : WebHttpBehavior{    protected override void AddServerErrorHandlers(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)    {        base.AddServerErrorHandlers(endpoint, endpointDispatcher);        //Remove all other error handlers        endpointDispatcher.ChannelDispatcher.ErrorHandlers.Clear();        //Add our own        endpointDispatcher.ChannelDispatcher.ErrorHandlers.Add(new CustomErrorHandler());    }}

The json error data contract

Specifies the json error format.Add properties here to change the error format.

[DataContractFormat]public class JsonError{    [DataMember]    public string Message { get; set; }    [DataMember]    public int FaultCode { get; set; }}

Using the error handler

Self-hosted

ServiceHost wsHost = new ServiceHost(new Webservice1(), new Uri("http://localhost/json")); ServiceEndpoint wsEndpoint = wsHost.AddServiceEndpoint(typeof(IWebservice1), new WebHttpBinding(), string.Empty);wsEndpoint.Behaviors.Add(new AddErrorHandlerBehavior());

App.config

<extensions>    <behaviorExtensions>      <add name="errorHandler"          type="WcfServiceLibrary1.ErrorHandlerElement, WcfServiceLibrary1" />    </behaviorExtensions>  </extensions> 


The only way I am able to get exception detail back is with

<serviceDebug includeExceptionDetailInFaults="true"/>

I tried the suggested method with extending HttpWebBehavior but when it is used with enableWebScript like the following:

<behavior name="JsonBehavior">    <myWebHttp/>    <enableWebScript/></behavior>

The WCF call will return status code 202 without anything information.If the configuration turns into

<behavior name="JsonBehavior">        <enableWebScript/>        <myWebHttp/>    </behavior>

You will get the nicely formatted message back but you lose all the json formatting functionality as well as request parameter parsing from enableWebScript, which completely defeats the purpose of using enableWebScript

I have attempted FaultContract as well but it appears to only work for Service References and not AJAX calls from JQuery.

It would be nice to be able to override WebScriptEnablingBehavior or the service itself to provide custom error handling.


I had the same problem as Bernd Bumüller and user446861 and at the end of it, I just reverted to using as the behaviour for my WCF service. Lo and behold, you don't need any of the IErrorHandler stuff anymore. You can just throw WebFaultException/WebFaultException types and everything is golden on the client side.

webHttp is basically the same as enableWebScript (webscript derives from webHttp from what I understand) minus the ASP.NET Ajax stuff (ScriptManager ServiceReference and all that). Since I am using jQuery, I didn't need the auto-generated JS service proxies and the other Ajax.net baggage. This worked wonderfully for my needs, so just thought I'd post a comment just in case anybody else is still looking for some info.