Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET Web API removing HttpError from responses

I'm building RESTful service using Microsoft ASP.NET Web API.

My problem concerns HttpErrors that Web API throws back to user when something go wrong (e.g. 400 Bad Request or 404 Not Found).

The problem is, that I don't want to get serialized HttpError in response content, as it sometimes provides too much information, therefore it violates OWASP security rules, for example:

Request:

http://localhost/Service/api/something/555555555555555555555555555555555555555555555555555555555555555555555

As a response, I get 400 of course, but with following content information:

{
 "$id": "1",
 "Message": "The request is invalid.",
 "MessageDetail": "The parameters dictionary contains a null entry for parameter 'id'  of non-nullable type 'System.Int32' for method 'MyNamespaceAndMethodHere(Int32)' in 'Service.Controllers.MyController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter."
}

Something like this not only indicates that my WebService is based on ASP.NET WebAPI technology (which isn't that bad), but also it gives some information about my namespaces, method names, parameters, etc.

I tried to set IncludeErrorDetailPolicy in Global.asax

GlobalConfiguration.Configuration.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Never;

Yeah, that did somehow good, now the result doesn't contain MessageDetail section, but still, I don't want to get this HttpError at all.

I also built my custom DelegatingHandler, but it also affects 400s and 404s that I myself generate in controllers, which I don't want to happen.

My question is: Is there any convinient way to get rid of serialized HttpError from response content? All I want user to get back for his bad requests is response code.

like image 744
Przemysław Kalita Avatar asked Jul 11 '13 09:07

Przemysław Kalita


People also ask

How do you handle exceptions in API?

You can customize how Web API handles exceptions by writing an exception filter. An exception filter is executed when a controller method throws any unhandled exception that is not an HttpResponseException exception.

How do I return an exception in Web API?

Return InternalServerError for Handled Exceptionscs file and locate the Get(int id) method. Add the same three lines within a try... catch block, as shown in Listing 2, to simulate an error. Create two catch blocks: one to handle a DivideByZeroException and one to handle a generic Exception object.

How do I use exception filter in Web API?

To apply the exception filter to all Web API controllers, the filter needs to register to GlobalConfiguration. Configuration. Filters collection. Following is a snapshot of Fiddler, when unhandled execution occurred in the action method.


2 Answers

What about using a custom IHttpActionInvoker ? Basically, you just have to send an empty HttpResponseMessage.

Here is a very basic example :

public class MyApiControllerActionInvoker : ApiControllerActionInvoker
{
    public override Task<HttpResponseMessage> InvokeActionAsync(HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken)
    {
        var result = base.InvokeActionAsync(actionContext, cancellationToken);

        if (result.Exception != null)
        {
            //Log critical error
            Debug.WriteLine("unhandled Exception ");

            return Task.Run<HttpResponseMessage>(() => new HttpResponseMessage(HttpStatusCode.InternalServerError));
        }
        else if (result.Result.StatusCode!= HttpStatusCode.OK)
        {
            //Log critical error
            Debug.WriteLine("invalid response status");

            return Task.Run<HttpResponseMessage>(() => new HttpResponseMessage(result.Result.StatusCode));
        }


        return result;
    }
}

In Global.asax

GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpActionInvoker), new MyApiControllerActionInvoker());

One other important thing you could do, not related to Web Api, is to remove excessive asp.net & IIS HTTP headers. Here is a good explanation.

like image 92
Cybermaxs Avatar answered Oct 10 '22 11:10

Cybermaxs


I believe your approach of using the message handler is correct because regardless of the component in the Web API pipeline that sets the status code to 4xx, message handler can clear out response body. However, you do want to differentiate between the ones you explicitly set versus the ones set by the other components. Here is my suggestion and I admit it is a bit hacky. If you don't get any other better solution, give this a try.

In your ApiController classes, when you throw a HttpResponseException, set a flag in request properties, like so.

Request.Properties["myexception"] = true;
throw new HttpResponseException(...);

In the message handler, check for the property and do not clear the response body, if the property is set.

var response = await base.SendAsync(request, cancellationToken);

if((int)response.StatusCode > 399 && !request.Properties.Any(p => p.Key == "myException"))
    response.Content = null;

return response;

You can package this a bit nicely by adding an extension method to HttpRequestMessage so that neither the ApiController nor the message handler knows anything about the hard-coded string "myException" that I use above.

like image 38
Badri Avatar answered Oct 10 '22 10:10

Badri