Mike Christensen
Mike Christensen

Reputation: 91628

Is there a way to handle HTTP responses in WCF when exceptions occur?

I have a web service that looks something like this:

[ServiceContract]
public class MyService
{
   [OperationContract]
   public void BreakStuff()
   {
      throw new MyException();
   }
}

It's not a very powerful web service right now, but you watch - it's gonna be great!

If I call BreakStuff(), WCF traps the exception, returns an HTTP 500 and optionally spits out a serialized stack trace if IncludeExceptionDetailsInFaults is set to true. I'd like to override this behavior and spit out my own custom error message object, and return HTTP 200. I want to do this because I think throwing exceptions in certain cases is cleaner than littering the code with try/catch blocks and having all web methods return some sort of Result object.

What I've done is implemented my own IDispatchMessageFormatter, which has the contract:

public interface IDispatchMessageFormatter
{
   void DeserializeRequest(Message message, object[] parameters);
   Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result);
}

SerializeReply gets called for normal HTTP 200 responses, however if the web method throws an exception, WCF never calls SerializeReply so I'm not given the chance to control the response output.

Does WCF provide the ability to customize error responses?

Upvotes: 2

Views: 885

Answers (1)

Garett
Garett

Reputation: 16828

You can implement a custom error handler by implementing the IErrorHandler interface. I've used this approach in the past to return custom error information in JSON format. In the ProvideFault method you can also change the response code. Below is a sample of one approach I've used.

public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{   
    fault = GetJsonResponseFromException(version, error);
    ConfigureMessageFormat(ref fault);
    ConfigureHttpReponse(ref fault, error);
}

protected virtual void ConfigureMessageFormat(ref Message fault)
{
    var formatting =
      new WebBodyFormatMessageProperty(WebContentFormat.Json);
    fault.Properties.Add(WebBodyFormatMessageProperty.Name, formatting);
}

protected virtual void ConfigureHttpReponse(ref Message fault, Exception error)
{
    var exception = error as WebFaultException<ServiceFault>;
    var statusCode = HttpStatusCode.InternalServerError;
    var description = HttpWorkerRequest
        .GetStatusDescription(Convert.ToInt32(statusCode));

    if (exception != null)
    {
        statusCode = exception.StatusCode;
        description = exception.Reason.Translations[0].Text;
    }

    var httpResponse = new HttpResponseMessageProperty()
    {
        StatusCode = statusCode,
        StatusDescription = description
    };

    httpResponse.Headers[HttpResponseHeader.ContentType] = "application/json";
    fault.Properties.Add(HttpResponseMessageProperty.Name, httpResponse);
}

Upvotes: 2

Related Questions