9

I've got a weird problem with returning a 400 status code with json on error.

In my controller, I've got something like:

if(!ModelState.IsValid)
{
    string[] errors = ModelState.Values
                            .SelectMany(x => x.Errors)
                            .Select(x => x.ErrorMessage).ToArray<string>();

    Response.StatusCode = (int)System.Net.HttpStatusCode.BadRequest;
    return Json(new { success = false, errors = errors }, JsonRequestBehavior.DenyGet);
}

This works fine on my development machine. I can get the errors in the ajax error method. But when I deploy to the server, the server doesn't return the JSON anymore. I always get responseText instead of reponseJSON. If I remove the Response.StatusCode it works fine.

This leads me to believe that the function 'returns' when I set the Response object's StatusCode property. Has this happened to anyone else? Anyone know the solution?

reggaemahn
  • 6,272
  • 6
  • 34
  • 59

2 Answers2

21

I finally figured out what the problem is. Posting this here as an answer for anyone else who may be pulling their hair out over this.

Set the following:

Response.TrySkipIisCustomErrors = true;

Make sure that this is set before you set the status code. I also figured out why it was working on my local machine and not on the test/uat servers. In my web.config, the CustomErrors was set to Off whereas on the servers it was set to On.

Seems like the server 'returns' as soon as it sees a BadRequest status code being written to the Response.

reggaemahn
  • 6,272
  • 6
  • 34
  • 59
  • 1
    Great! BTW you don't need it under IIS 10, but still need it under IIS7. At least this is my experience (inconsistency is pain in a ass, moving between development and production causes unexpected challenges) – Mike Keskinov Aug 04 '17 at 23:00
  • 1
    Thanks for posting the answer. I was having the same problem when publishing in AWS Elasticbeanstalk servers. – Rafael Mar 19 '18 at 14:19
  • 1
    Thank you so much for the answer and explanation on why it didn't work. It worked for me. – aspnetdeveloper May 08 '19 at 19:23
  • Thanks, this saved my life! – hyphen Jan 16 '20 at 21:48
1

Well, even though you are explicitly casting, Response.StatusCode is a child element of Response.

In most cases, the easiest way I find and following "best practices" for creating WebAPI's:

First, your method signature would change from:

public JsonResult Action() { ... }

to

public IHttpActionResult Action { ... }

then instead of returning Json() you would use the following:

return Content(HttpStatusCode.BadRequest, new {success = false, errors = errors }, Configuration.Formatters.JsonFormatter);

where the final variable, Configuration.Formatters.JsonFormatter is optional--remember, Json is the default return type (or ASP.NET allows for content negotiation and will follow what the client requests).

Hope that helps.

  • Hey, thanks. Unfortunately, I'd already tried that and it hadn't worked. I've added as an answer, what finally worked. Although I'd love to know the source of 'best practices' for the things you've mentioned. – reggaemahn May 19 '16 at 04:19
  • @JeevanJose interesting, what issues were you having using the above code? Same exact bug? As far as best practices go, I'm going based on what's recommended when crafting API's by most .NET experts (Shawn Wildermuth on Pluralsight has a few great ones in particular: https://app.pluralsight.com/library/courses/web-api-design/table-of-contents https://app.pluralsight.com/library/courses/implementing-restful-aspdotnet-web-api/table-of-contents and finally https://app.pluralsight.com/library/courses/aspdotnet-bestpractices-models/table-of-contents ). – Fernando Rodriguez May 21 '16 at 06:22