17

我使用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),但我遇到的问题是返回。在控制器上,我经常返回 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);. 此外,我检查了响应,返回的 statusCode 实际上是 200,所以服务器没有失败 - jQuery 只是说它是。

4

1 回答 1

37

该问题是由从 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 解析器在空字符串上抛出异常,并触发一个以fail()回调结尾的代码链。

一种解决方法是在成功时将其从服务器传回,而无需其他信息:

return Json(new{});

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

return Json(true);


更新

Musa 在 MVC 的这种行为下方指出似乎已被破坏。这个单独的 Stack Overflow 回答Using JSON.NET as the default JSON serializer in ASP.NET MVC 3 - 可能吗?涵盖如何让 MVC 返回 null Json(null)——基本上,使用 Json.NET 而不是 ASP.NET MVC 的内置 JSON 序列化程序。这是我最终使用的解决方案。

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


更新 2

Json.NET 中 ISO 8601 日期的默认实现在尝试使用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');

但这会引发异常:

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

于 2013-04-11T02:55:10.737 回答