The problem was caused by upgrading from jQuery 1.8 to 1.9. In jQuery 1.7 and 1.8, this in MVC:
return Json(null);
was accepted as valid JSON and interpreted as null. Technically, this sends a blank string back to the client with HTTP 200, and that's good enough for jQuery <1.9.
But now (we're using jQuery 1.9.1), it attempts to parse the empty string as JSON, jQuery's JSON parser throws an exception on empty string, and that triggers a code chain that ends in a fail()
callback instead.
A workaround is to instead pass this back from the server on success with no other information:
return Json(new{});
That passes muster with jQuery's JSON parser and all is well. This also works:
return Json(true);
Update
Musa notes below this behavior by MVC seems broken. This separate Stack Overflow answer to Using JSON.NET as the default JSON serializer in ASP.NET MVC 3 - is it possible? covers how to get MVC to return null for Json(null)
- basically, use Json.NET instead of ASP.NET MVC's built-in JSON serializer. This is the solution I ultimately ended up using.
You need to use a slightly modified version of that answer to fix this however - code is below. Basically, don't include the if
statement checking for null before passing to serialize, or you're right back in the same predicament.
Update 2
The default implementation of ISO 8601 Dates in Json.NET breaks Internet Explorer 9 and below when it attempts to parse it with new Date(...)
. In other words, these parse fine in Internet Explorer 9:
var date = new Date('2014-09-18T17:21:57.669');
var date = new Date('2014-09-18T17:21:57.600');
But this throws an exception:
var date = new Date('2014-09-18T17:21:57.6');
Internet Explorer 9's Date() implementation can't cope with anything but exactly three millisecond places. To fix this you have to override the Json.NET date format to force it. Included in the code below.
public class JsonNetResult : JsonResult
{
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
throw new ArgumentNullException("context");
var response = context.HttpContext.Response;
response.ContentType = !String.IsNullOrEmpty(ContentType) ? ContentType : "application/json";
if (ContentEncoding != null)
response.ContentEncoding = ContentEncoding;
var settings = new JsonSerializerSettings
{
Converters = new[] {new IsoDateTimeConverter
{
DateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.fffK"
}}
};
var jsonSerializer = JsonSerializer.Create(settings);
jsonSerializer.Serialize(response.Output, Data);
}
}
A Gist that demonstrates how to tie this into a BaseController:
https://gist.github.com/b9chris/6991b341e89bb0a4e6d801d02dfd7730