asp.netjsonasp.net-mvc-5unobtrusive-ajax

JSON.parse error: unexpected character after project release


I used jquery.unobtrusive-ajax in my view. In this view, there is a form that is submit via ajax.

In the action if the modelsets is invalid, I will return the errors through the code below

 Response.StatusCode = (int)HttpStatusCode.BadRequest;
 return Json(new { errors = ModelState.Values.SelectMany(v => v.Errors) });

And in the view through the code below I show the errors to the user.

        function failed(err1) {
        obj = JSON.parse(err1.responseText).errors;
        console.log(obj);
        EmptyValidationErrors();
        jQuery.each(obj, function (i) {
            //alert(obj[i].ErrorMessage);
            AddValidationError(obj[i].ErrorMessage);
            ShowValidationErrors();
        });
    }

SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data


Solution

  • CustomErrors mode

    It's IIS behavior to handle responses whith 400 http code. So, you need to remove that line

    Response.StatusCode = (int)HttpStatusCode.BadRequest;
    

    and add extra data to your response. like this:

    if (ModelState.IsValid) {
      return Json(new { success = true });
    }
    
    return Json(new { success = false, errors = ModelState.Values.SelectMany(v => v.Errors) });
    

    And read this in your JS code like this:

    $.ajax({
      url: url,
      method: 'POST',
      success: function(data) {
        if (!data.success) {
          $.each(data.errors, function(i, error) {
             AddValidationError(error.ErrorMessage);
          });
          ShowValidationErrors();
        }
      }
    });
    

    In your Web.config you can find section like that:

    <customErrors mode="Off">
    </customErrors>
    

    mode="Off" rewrite to mode="On" during deploy process, so in production any responses whith 400 code handle by another way, than while debugging. In Web.Release.config you can find what exactly rewriting in this section

    Update

    Another solution:

    Response.TrySkipIisCustomErrors = true;
    Response.StatusCode = (int)HttpStatusCode.BadRequest;
    return Json(new { errors = ModelState.Values.SelectMany(v => v.Errors) });
    

    This will stop handling custom error mode="On" and resposne will contains your json with errors.