从ASP.NET MVC返回null时,jQuery post JSON失败

我使用ASP.NET MVC从jQuery发布JSON,并使用这个小库函数获取一些JSON:

(function($) { $.postJson = function(url, data) { return $.ajax({ url: url, data: JSON.stringify(data), type: 'POST', dataType: 'json', contentType: 'application/json; charset=utf-8' }); }; })(jQuery); 

显然我会这样称呼:

 $('#button').click(function() { $.postJson('/controller/action', { Prop1: 'hi', Prop2: 'bye' }) .done(function(r) { alert('It worked.'); }) .fail(function(x) { alert('Fail! ' + x.status); }); }); 

ASP.NET MVC 3和ASP.NET MVC 4支持事物的提交方面(在此之前您需要扩展ASP.NET MVC来处理提交JSON),但我遇到的问题是返回。 在Controller上我经常返回null,基本上说“成功,没别的说”,如:

 [HttpPost] public JsonResult DoSomething(string Prop1, string Prop2) { if (doSomething(Prop1, Prop2) return Json(null); // Success return Json(new { Message = "It didn't work for the following reasons" }); } 

我经常使用这种模式,它工作正常 – 我的成功/完成回调被调用,一切都很好。 但是最近我升级了ASP.NET MVC和jQuery,它停止了工作 – 相反,每当我return Json(null);时,我的失败回调就会被调用return Json(null); 。 此外,我已经检查了响应并且返回的statusCode实际上是200,所以服务器没有失败 – jQuery只是说它是。

问题是由jQuery 1.8升级到1.9引起的。 在jQuery 1.7和1.8中,这在MVC中:

 return Json(null); 

被接受为有效的JSON并被解释为null。 从技术上讲,这会使用HTTP 200将空字符串发送回客户端,这对于jQuery <1.9来说已经足够了。

但是现在(我们正在使用jQuery 1.9.1),它尝试将空字符串解析为JSON,jQuery的JSON解析器在空字符串上抛出exception,并触发以fail()回调结束的代码链。

解决方法是在成功时将其从服务器传回,而不提供其他信息:

 return Json(new{}); 

这通过了jQuery的JSON解析器,一切都很顺利。 这也有效:

 return Json(true); 

更新

Musa在MVC下面注意到这种行为似乎已经破裂。 这个单独的Stack Overflow回答使用JSON.NET作为ASP.NET MVC 3中的默认JSON序列化程序 – 是否可能? 介绍如何让MVC为Json(null)返回null – 基本上,使用Json.NET而不是ASP.NET MVC的内置JSON序列化程序。 这是我最终使用的解决方案。

您需要使用该答案的略微修改版本来修复此问题 – 代码如下。 基本上,在传递给序列化之前不要包含if语句检查null,否则你就会回到同样的困境中。

更新2

Json.NET中的ISO 8601日期的默认实现在尝试使用new Date(...)解析时会破坏Internet Explorer 9及更低版本。 换句话说,这些在Internet Explorer 9中解析得很好:

 var date = new Date('2014-09-18T17:21:57.669'); var date = new Date('2014-09-18T17:21:57.600'); 

但这引发了一个例外:

 var date = new Date('2014-09-18T17:21:57.6'); 

Internet Explorer 9的Date()实现无法应对除了三毫秒之外的任何地方。 要解决此问题,您必须覆盖Json.NET日期格式以强制它。 包含在下面的代码中。

 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); } } 

一个演示如何将其绑定到BaseController的要点:

https://gist.github.com/b9chris/6991b341e89bb0a4e6d801d02dfd7730