asp.net Web Api - Default Error Messages

2019-02-12 22:12发布

问题:

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:

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;
        });
    }
}


回答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; }
   }