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

Chr*_*ini 14 ajax asp.net-mvc null jquery 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);
Run Code Online (Sandbox Code Playgroud)

显然我会这样称呼:

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

ASP.NET MVC 3和ASP.NET MVC 4支持事物的提交方面(在此之前您需要扩展ASP.NET MVC以处理提交JSON),但我遇到的问题是返回.在控制器上我经常返回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" });
}
Run Code Online (Sandbox Code Playgroud)

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

Chr*_*ini 36

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

return Json(null);
Run Code Online (Sandbox Code Playgroud)

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

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

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

return Json(new{});
Run Code Online (Sandbox Code Playgroud)

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

return Json(true);
Run Code Online (Sandbox Code Playgroud)


更新

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

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


更新2

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

var date = new Date('2014-09-18T17:21:57.669');
var date = new Date('2014-09-18T17:21:57.600');
Run Code Online (Sandbox Code Playgroud)

但这引发了一个例外:

var date = new Date('2014-09-18T17:21:57.6');
Run Code Online (Sandbox Code Playgroud)

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

一个Gist,演示如何将其绑定到BaseController:

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