web-dev-qa-db-ja.com

ASP.NET MVCからnullを返すと、jQuery postJSONが失敗する

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 MVC3とASP.NETMVC 4は、送信側をサポートしています(以前は、JSONの送信を処理するためにASP.NET MVCを拡張する必要がありました)が、私が直面している問題は戻ってきました。コントローラーでは、基本的に「成功、他に何も言うことはありません」と言うために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);のたびにfailコールバックが呼び出されます。さらに、応答を調べたところ、返されるstatusCodeは実際には200であるため、サーバーに障害は発生していません。jQueryは障害が発生していると言っているだけです。

14
Chris Moschini

この問題は、jQuery1.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);
_


更新

MVCによるこの動作の下のMusaノートは壊れているようです。これ ASP.NET MVC 3のデフォルトのJSONシリアライザーとしてJSON.NETを使用するに対する個別のスタックオーバーフローの回答-可能ですか? = Json(null)に対してMVCがnullを返すようにする方法について説明します-基本的に、ASP.NETMVCの組み込みJSONシリアライザーの代わりにJson.NETを使用します。これは私が最終的に使用することになったソリューションです。

ただし、これを修正するには、その回答のわずかに変更されたバージョンを使用する必要があります-コードは以下のとおりです。基本的に、シリアル化に渡す前にnullをチェックするifステートメントを含めないでください。そうしないと、同じ苦境に戻ってしまいます。


アップデート2

Json.NETでのISO8601日付のデフォルトの実装は、new Date(...)で解析しようとすると、 Internet Explorer 9 以下になります。つまり、これらはInternet Explorer9で正常に解析されます。

_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()実装は、正確に3ミリ秒の場所以外には対応できません。これを修正するには、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/6991b341e89bb0a4e6d801d02dfd77

36
Chris Moschini