Return Mvc.JsonResult plus set Response.StatusCode
Asked Answered
C

3

43

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

Coronach answered 19/6, 2013 at 4:42 Comment(6)
Why do you want to return 400? Isn't this just an error page with a friendly error messagePhotocompose
#6123925 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'.Coronach
I would check the error field in the JSON instead of the http status codePhotocompose
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 worksCurse
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.Coronach
It could be an issue with IIS Custom errors. Maybe try setting Response.TrySkipIisCustomErrors = true; linkFinicking
P
60

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.

Penetrant answered 17/7, 2013 at 6:3 Comment(3)
@Penetrant 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!Tetragon
I had to add <httpErrors errorMode="Custom" existingResponse="Auto"> as well because existingResponse="Replace" would ignore the TrySkipIisCustomErrors!Abutment
Like so many people, I've had weird IIS issues before, but I will be honest, this one takes the biscuit.Cheer
S
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.

Semi answered 19/9, 2017 at 12:11 Comment(3)
Please merge this into the Mvc API .. Dear god this is what most would consider essential.Cheer
I would just extend to include <T> IE : public class JsonResultWithHttpStatusCode<T>Cheer
@Cheer What's T?Lumisterol
M
1

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

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

Mohamed answered 15/11, 2020 at 9:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.