9

Is there a way of changing Web Api's default behavior for error messages, such as:

GET /trips/abc

Responds with (paraphrased):

HTTP 500 Bad Request

{
    "Message": "The request is invalid.",
    "MessageDetail": "The parameters dictionary contains a null entry for parameter 'tripId' of non-nullable type 'System.Guid' for method 'System.Net.Http.HttpResponseMessage GetTrip(System.Guid)' in 'Controllers.TripController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter."
}

I'd like to avoid giving out this rather detailled information about my code, and instead replace it with something like:

HTTP 500 Bad Request
{
    error: true,
    error_message: "invalid parameter"
}

I'd be able to do this inside the UserController, but the code execution doesn't even go that far.

edit:

I've found a way of removing detailed error messages from the output, using this line of code in Global.asax.cs:

GlobalConfiguration.Configuration.IncludeErrorDetailPolicy =
IncludeErrorDetailPolicy.LocalOnly;

This produces a message like this:

{
    "Message": "The request is invalid."
}

which is better, however not exactly what I want - We've specified a number of numeric error codes, which are mapped to detailed error messages client-side. I would like to only output the appropriate error code (that I'm able to select prior to output, preferrably by seeing what kind of exception occured), for example:

{ error: true, error_code: 51 }
1
  • I know this is bordering on needlessly picky, but shouldn't a Bad Request be an HTTP 400, rather than 500? Do you mind if I edit it? Commented May 16, 2019 at 16:07

2 Answers 2

9

You might want to keep the shape of the data as the type HttpError even if you want to hide detailed information about the actual exception. To do that, you can add a custom DelegatingHandler to modify the HttpError that your service throws.

Here is a sample of how the DelegatingHandler might look like:

public class CustomModifyingErrorMessageDelegatingHandler : DelegatingHandler
{
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        return base.SendAsync(request, cancellationToken).ContinueWith<HttpResponseMessage>((responseToCompleteTask) =>
        {
            HttpResponseMessage response = responseToCompleteTask.Result;

            HttpError error = null;
            if (response.TryGetContentValue<HttpError>(out error))
            {
                error.Message = "Your Customized Error Message";
                // etc...
            }

            return response;
        });
    }
}
Sign up to request clarification or add additional context in comments.

2 Comments

In case you wonder where to add it, it can be added by calling config.MessageHandlers.Add(new YourDelegatingHandler()), usually in the Register(HttpConfiguration config) method in your startup logic.
Instead of replacing the response content after it's built, shouldn't we rather be customizing the class/service that is responsible for building that response in the first place?
2

Maggie's answer worked for me as well. Thanks for posting!

Just wanted to some bits to her code for additional clarification:

HttpResponseMessage response = responseToCompleteTask.Result;
HttpError error = null;

if ((!response.IsSuccessStatusCode) && (response.TryGetContentValue(out error)))
{
    // Build new custom from underlying HttpError object.
    var errorResp = new MyErrorResponse();

    // Replace outgoing response's content with our custom response
    // while keeping the requested MediaType [formatter].
    var content = (ObjectContent)response.Content;
    response.Content = new ObjectContent(typeof (MyErrorResponse), errorResp, content.Formatter);
}

return response;

Where:

   public class MyErrorResponse
   {
       public MyErrorResponse()
       { 
          Error = true; 
          Code = 0; 
       }

       public bool Error { get; set; }
       public int Code { get; set; }
   }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.