41

Project: ASP MVC 4 running under .net 4.0 framework:

When running an application under VS 2010 express (or deployed and running under IIS 7.5 on my local machine) the following (pseudocode) result from an action works as expected

[HttpPost]
public ActionResult PostWord(Model model)
{
   ....
   Response.StatusCode = 400;
   Return new JsonResult { data = new {fieldName = "Word", error = "Not really a word!" } };

(and I have assigned ContentType and ContentEncoding properties of the JsonResult object, with no difference in behaviour)

When the deployable is moved onto a web host (using IIS 7), firebug is telling me that the response is as expected (400) but there is no JSON in the response (ie there is no text of any kind). If I remove the line

Response.StatusCode = 400;

from the action, the JSON is perfectly formed in the response, but of course the response status code is 200 (OK), which interferes with the consuming javascript and appropriate function call.

Any thoughts on what might be going on and how to fix this? Thank you

Brent
  • 3,907
  • 3
  • 31
  • 46
  • Why do you want to return 400? Isn't this just an error page with a friendly error message – TGH Jun 19 '13 at 04:48
  • http://stackoverflow.com/questions/6123425/rest-response-code-for-invalid-data maybe I should do things differently, but JSON is returned regardless - the response code gives the postback function information in order to know what to do with the JSON. 200 to me means 'database updated as requested'. – Brent Jun 19 '13 at 04:54
  • I would check the error field in the JSON instead of the http status code – TGH Jun 19 '13 at 04:57
  • IIS7 hides detailed error messages by default, so you don't get any content when an error is returned. Try changing the iss7 setup to return detailed error messages and see if that works – Slicksim Jun 19 '13 at 08:24
  • checking JSON instead of status code - current architecture = all good, return partialview (ie html), or, if any problems - describe problems in JSON. I would have to try and parse the html in a try/catch block checking for an error, and then if it is html, not know if it is a correct response or a custom error page served; rather than using the very useful onError & onSuccess unobtrusive ajax attributes. As for errors - I have Elmah running. no errors are being logged, the response is empty. – Brent Jun 19 '13 at 09:20
  • 25
    It could be an issue with IIS Custom errors. Maybe try setting `Response.TrySkipIisCustomErrors = true;` [link](http://briancaos.wordpress.com/2012/06/12/custom-404-page-ignored-by-iis-7/) – Walter Jun 27 '13 at 22:52

3 Answers3

57

I had this exact same problem; in order to make sure that the correct answer is not buried in the comments (as it was for me), I want to reiterate @Sprockincat's comment:

For me at least, it was indeed an issue with IIS Custom errors, and can be solved with:

Response.TrySkipIisCustomErrors = true;

@Sprockincat - you should get credit for this. I'm just making it more visible because it's such a subtle fix to a problem that is quite difficult to diagnose.

Robert
  • 1,407
  • 1
  • 13
  • 24
  • Thanks for this, invaluable! – Henry Wilson Aug 18 '14 at 11:46
  • 3
    @Robert if I could upvote this answer every day for the next year I would!! Thanks for this! This frikkin' problem had me digging for the past 12 hours! Thank you thank you thank you thank you. And thanks to Brent for the opening post! – Shawn de Wet Sep 06 '14 at 10:07
  • 1
    I had to add as well because existingResponse="Replace" would ignore the TrySkipIisCustomErrors! – Jacob McKay Mar 31 '16 at 20:31
  • Like so many people, I've had weird IIS issues before, but I will be honest, this one takes the biscuit. – Pogrindis Oct 31 '18 at 11:57
3

I've created a subclass of JsonResult that allows you to specify the HttpStatusCode.

public class JsonResultWithHttpStatusCode : JsonResult
{

    private int _statusCode;
    private string _statusDescription;

    public JsonResultWithHttpStatusCode(object data, HttpStatusCode status) 
    {
        var code = Convert.ToInt32(status);
        var description = HttpWorkerRequest.GetStatusDescription(code);
        Init(data, code, description);
    }

    public JsonResultWithHttpStatusCode(object data, int code, string description)
    {
        Init(data, code, description);
    }

    private void Init(object data, int code, string description)
    {
        Data = data;
        _statusCode = code;
        _statusDescription = description;
    }

    public override void ExecuteResult(ControllerContext context)
    {
        context.HttpContext.Response.StatusCode = _statusCode;
        context.HttpContext.Response.StatusDescription = _statusDescription;
        base.ExecuteResult(context);
    }
}

Then you can return this as your result and the status code will get set on the response. You can also test the status code on the result in your tests.

Richard Garside
  • 82,523
  • 9
  • 75
  • 82
0

For anyone looking for this - in ASP.NET Core you can set the StatusCode property of JsonResult.

https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.jsonresult.statuscode

arni
  • 1,896
  • 16
  • 12