jquery - sending - mvc ajax post
jQuery post JSON falla al devolver nulo desde ASP.NET MVC (1)
Uso ASP.NET MVC para publicar JSON desde jQuery, y recuperar algo de JSON, usando esta pequeña función de biblioteca:
(function($) {
$.postJson = function(url, data) {
return $.ajax({
url: url,
data: JSON.stringify(data),
type: ''POST'',
dataType: ''json'',
contentType: ''application/json; charset=utf-8''
});
};
})(jQuery);
Así que obviamente llamaré esto como:
$(''#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 y ASP.NET MVC 4 son compatibles con el lado de envío de cosas (antes de eso, era necesario extender ASP.NET MVC para manejar el envío de JSON), pero el problema con el que me estoy encontrando es a la vuelta. En el controlador a menudo devuelvo nulo para decir básicamente "éxito, nada más que decir", como:
[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" });
}
Utilizo este patrón con frecuencia y funciona bien: se llama a mi devolución / devolución de llamada realizada y todo está bien. Pero recientemente actualicé ASP.NET MVC y jQuery, y dejó de funcionar; en cambio, se llama a mi devolución de llamada fallida cada vez que return Json(null);
. Además, he inspeccionado la respuesta y el statusCode que se devuelve es de hecho 200, por lo que el servidor no está fallando, jQuery solo dice que sí.
El problema fue causado por la actualización de jQuery 1.8 a 1.9. En jQuery 1.7 y 1.8, esto en MVC:
return Json(null);
fue aceptado como JSON válido e interpretado como nulo. Técnicamente, esto envía una cadena en blanco al cliente con HTTP 200, y eso es suficiente para jQuery <1.9.
Pero ahora (estamos usando jQuery 1.9.1), intenta analizar la cadena vacía como JSON, el analizador JSON de jQuery arroja una excepción en una cadena vacía, y eso desencadena una cadena de código que termina en una devolución de llamada fail()
.
Una solución alternativa es, en cambio, pasarla al servidor si no tiene otra información:
return Json(new{});
Eso pasa junta con el analizador JSON de jQuery y todo está bien. Esto también funciona:
return Json(true);
Actualizar
Las notas de Musa debajo de este comportamiento por MVC parecen rotas. Este desbordamiento de pila por separado responde al uso de JSON.NET como el serializador JSON predeterminado en ASP.NET MVC 3, ¿es posible? cubre cómo hacer que MVC devuelva nulo para Json(null)
; básicamente, usa Json.NET en lugar del serializador JSON incorporado de ASP.NET MVC. Esta es la solución que finalmente terminé usando.
Sin embargo, debe usar una versión ligeramente modificada de esa respuesta para solucionarlo: el código está a continuación. Básicamente, no incluya la instrucción if
que verifica null antes de pasar a serializar, o está de vuelta en la misma situación.
Actualización 2
La implementación predeterminada de Fechas ISO 8601 en Json.NET interrumpe Internet Explorer 9 y versiones posteriores cuando intenta analizarlo con una new Date(...)
. En otras palabras, estos parse multa en Internet Explorer 9:
var date = new Date(''2014-09-18T17:21:57.669'');
var date = new Date(''2014-09-18T17:21:57.600'');
Pero esto arroja una excepción:
var date = new Date(''2014-09-18T17:21:57.6'');
La implementación de Date () de Internet Explorer 9 no puede hacer frente a nada excepto lugares exactamente de tres milisegundos. Para solucionarlo, debe sobrescribir el formato de fecha de Json.NET para forzarlo. Incluido en el código a continuación.
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);
}
}
Una Gist que demuestra cómo vincular esto en un BaseController:
https://gist.github.com/b9chris/6991b341e89bb0a4e6d801d02dfd7730