Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

asp.net Web Api - Default Error Messages

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 }
like image 438
doque Avatar asked Oct 22 '12 14:10

doque


2 Answers

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;
        });
    }
}
like image 105
Maggie Ying Avatar answered Sep 21 '22 09:09

Maggie Ying


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; }
   }
like image 34
ewoo Avatar answered Sep 19 '22 09:09

ewoo