"Primitiva JSON no válida" en el procesamiento Ajax

101

Recibo un error en una llamada ajax de jQuery.

Aquí está mi función jQuery:

function DeleteItem(RecordId, UId, XmlName, ItemType, UserProfileId) {
    var obj = {
        RecordId: RecordId,
        UserId: UId,
        UserProfileId: UserProfileId,
        ItemType: ItemType,
        FileName: XmlName
    };
    var json = Sys.Serialization.JavaScriptSerializer.serialize(obj);

    $.ajax({
        type: "POST",
        url: "EditUserProfile.aspx/DeleteRecord",
        data: json,
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        async: true,
        cache: false,
        success: function(msg) {
            if (msg.d != null) {
                RefreshData(ItemType, msg.d);
            }
        },
        error: function(XMLHttpRequest, textStatus, errorThrown) {
            alert("error occured during deleting");
        }
    });
}

y este es mi WebMethod:

[WebMethod]
public static string DeleteRecord(Int64 RecordId, Int64 UserId, Int64 UserProfileId, string ItemType, string FileName) {
    try {
        string FilePath = HttpContext.Current.Server.MapPath(FileName);

        XDocument xmldoc = XDocument.Load(FilePath);
        XElement Xelm = xmldoc.Element("UserProfile");
        XElement parentElement = Xelm.XPathSelectElement(ItemType + "/Fields");

        (from BO in parentElement.Descendants("Record")
         where BO.Element("Id").Attribute("value").Value == RecordId.ToString()
         select BO).Remove();
        XDocument xdoc = XDocument.Parse(Xelm.ToString(), LoadOptions.PreserveWhitespace);
        xdoc.Save(FilePath);

        UserInfoHandler obj = new UserInfoHandler();
        return obj.GetHTML(UserId, UserProfileId, FileName, ItemType, RecordId, Xelm).ToString();
    } catch (Exception ex) {
        HandleException.LogError(ex, "EditUserProfile.aspx", "DeleteRecord");
    }
    return "success";
}

¿Alguien puede decirme qué está mal en mi código?

Recibo este error:

{
    "Message":"Invalid JSON primitive: RecordId.",
    "StackTrace":"
       at System.Web.Script.Serialization.JavaScriptObjectDeserializer.DeserializePrimitiveObject()
       at System.Web.Script.Serialization.JavaScriptObjectDeserializer.DeserializeInternal(Int32 depth)
       at System.Web.Script.Serialization.JavaScriptObjectDeserializer.BasicDeserialize(String input, Int32 depthLimit, JavaScriptSerializer serializer)
       at System.Web.Script.Serialization.JavaScriptSerializer.Deserialize(JavaScriptSerializer serializer, String input, Type type, Int32 depthLimit)
       at System.Web.Script.Serialization.JavaScriptSerializer.Deserialize[T](String input)
       at System.Web.Script.Services.RestHandler.GetRawParamsFromPostRequest(HttpContext context, JavaScriptSerializer serializer)
       at System.Web.Script.Services.RestHandler.GetRawParams(WebServiceMethodData methodData, HttpContext context)
       at System.Web.Script.Services.RestHandler.ExecuteWebServiceCall(HttpContext context, WebServiceMethodData methodData)",
    "ExceptionType":"System.ArgumentException"
}
Radhi
fuente
Lo que no entiendo es. El javascript trata sobre AddAlbumToMyProfile, mientras que el WebMethod se llama DeleteRecord. ¿Está seguro de que nos muestra los códigos correctos?
jitter
¿Alguna posibilidad de que también pueda capturar cómo se ve el POST (usando firebug o lo que sea) y agregarlo a la pregunta? No estoy seguro de si es la forma en que está codificando los datos antes de enviarlos, pero también puede intentar serializarlos usando esto ( json.org/json2.js ).
R0MANARMY

Respuestas:

135

Solo una adivina qué contiene la variable jsondespués

var json = Sys.Serialization.JavaScriptSerializer.serialize(obj);?

Si es un objeto json válido, {'foo':'foovalue', 'bar':'barvalue'}entonces jQuery podría no enviarlo como datos json, sino serializarlo para foor=foovalue&bar=barvalueobtener el error"Invalid JSON primitive: foo"

En su lugar, intente configurar los datos como una cadena

$.ajax({
    ...
    data: "{'foo':'foovalue', 'bar':'barvalue'}", //note the additional quotation marks
    ...
})

De esta manera, jQuery debería dejar los datos en paz y enviar la cadena como está al servidor, lo que debería permitir que ASP.NET analice el lado del servidor json.

estar nervioso
fuente
5
gracias por la aclaración, agregue un comentario más, siempre puede hacer como JSON.stringify ({foo: 'foovalue', bar: 'barvalue'}) para una vida más fácil
Elaine
Una década tarde en la fiesta, pero sigue siendo relevante: no es JSON válido. Las cadenas (incluidos los nombres de propiedad) en JSON deben usar comillas dobles , por lo que debería ser así {"foo": "foovalue", "bar": "barvalue"}. El uso de comillas simples es un error de sintaxis.
Mike 'Pomax' Kamermans
108

Utilizando

data : JSON.stringify(obj)

en la situación anterior habría funcionado, creo.

Nota: Debe agregar la biblioteca json2.js, todos los navegadores no admiten ese objeto JSON (IE7-) Diferencia entre json.js y json2.js

Andrés
fuente
3
¡Gracias! Cuando se utilizan clases JS simples, esto funciona. Cambié data: { JSON.stringify(obj) }a data: JSON.stringify(obj)(Mi clase javascript / JSON para serializar es del estilo var myObj = { title: "x", subclass = someVar, ... } )
lko
1
Tenga en cuenta que esta es la solución siempre que necesite enviar JSON ( lo que podría hacer con los servicios web asp.net ). En otros casos, podría ser más fácil simplemente eliminarcontentType y dejar que jQuery pase los datos codificados por formulario.
GSerg
19

Como indica jitter, la $.ajaxfunción serializa cualquier objeto / matriz utilizado como dataparámetro en un formato codificado en URL. Curiosamente, el dataTypeparámetro solo se aplica a la respuesta del servidor, y no a los datos de la solicitud.

Después de encontrar el mismo problema, descargué y usé el complemento jquery-json para codificar correctamente los datos de la solicitud en ScriptService. Luego, usó la $.toJSONfunción para codificar los argumentos deseados para enviarlos al servidor:

$.ajax({
    type: "POST",
    url: "EditUserProfile.aspx/DeleteRecord",
    data: $.toJSON(obj),
    contentType: "application/json; charset=utf-8",
    dataType: "json"
    ....
});
leepowers
fuente
2
gracias por señalar que el dataparámetro es ignorado por la llamada.
Noel Abrahams
3
Esto funciona, pero cambiar data: { JSON.stringify(obj) }a data: JSON.stringify(obj)funcionó para mí si su clase de javascript es del estilo var myObj = { title: "x", subclass = someVar, ... } gracias al punto sobre la codificación de datos.
lko
19

está funcionando algo como esto

data: JSON.stringify({'id':x}),
Jessica Sáenz
fuente
3
Esta respuesta apareció en la cola de revisión de baja calidad, presumiblemente porque no proporciona ninguna explicación del código. Si este código responde a la pregunta, considere agregar algún texto que explique el código en su respuesta. De esta manera, es mucho más probable que obtenga más votos a favor y ayude al interrogador a aprender algo nuevo.
lmo
Quiero pasar dos parámetros: una matriz de objeto complejo y un número entero. Lo hago: datos: {elementos: JSON.stringify (myarray), myId: value}.
A.Dara
gracias por publicar la respuesta. esto funcionó para mí.
ZMAX
13

Jquery Ajax enviará los datos de forma predeterminada como parámetros de cadena de consulta como:

RecordId=456&UserId=123

a menos que la processDataopción esté establecida en false, en cuyo caso se enviará como objeto al servidor.

  • contentType La opción es para el servidor en qué formato el cliente ha enviado los datos.

  • dataType La opción es para el servidor que indica qué tipo de datos del cliente espera recibir del servidor.

No especifique contentType para que el servidor los analice como parámetros de cadena de consulta, no como json.

O

Utilice contentType como 'aplicación / json; charset = utf-8 'y use JSON.stringify (objeto) para que el servidor pueda deserializar json desde la cadena.

T Gupta
fuente
5

Supongo que @jitter tenía razón en su suposición, pero su solución no funcionó para mí.

Esto es lo que funcionó:

$.ajax({
    ...
    data: "{ intFoo: " + intFoo + " }",
    ...
});

No lo he intentado, pero creo que si el parámetro es una cadena, debería ser así:

$.ajax({
    ...
    data: "{ intFoo: " + intFoo + ", strBar: '" + strBar + "' }",
    ...
});
Diego
fuente
9
Si tuviera que escribir un código como ese (cadena concat) para crear objetos JSON, me mataría (en sentido figurado). Tiene que haber una mejor manera.
PandaWood
3

Estaba enfrentando el mismo problema, lo que obtuve con una buena solución es la siguiente:

Prueba esto...

$.ajax({
    type: "POST",
    url: "EditUserProfile.aspx/DeleteRecord",
    data: '{RecordId: ' + RecordId + ', UserId: ' + UId + ', UserProfileId:' + UserProfileId + ', ItemType: \'' + ItemType + '\', FileName: '\' + XmlName + '\'}',
    contentType: "application/json; charset=utf-8",
    dataType: "json",
    async: true,
    cache: false,
    success: function(msg) {
        if (msg.d != null) {
            RefreshData(ItemType, msg.d);
        }
    },
    error: function(XMLHttpRequest, textStatus, errorThrown) {
        alert("error occured during deleting");
    }
});

Tenga en cuenta que aquí para el parámetro de tipo de cadena he utilizado (\ ') carácter de secuencia de escape para denotarlo como valor de cadena.

Sohel Pathan
fuente
datos: "{Notas: \" "+ $ ('# txtNotes'). val () +" \ "}
bestinamir
1

Si formatea manualmente JSON, hay un validador muy útil aquí: jsonlint.com

Utilice comillas dobles en lugar de comillas simples:

Inválido:

{
    'project': 'a2ab6ef4-1a8c-40cd-b561-2112b6baffd6',
    'franchise': '110bcca5-cc74-416a-9e2a-f90a8c5f63a0'
}

Válido:

{
    "project": "a2ab6ef4-1a8c-40cd-b561-2112b6baffd6",
    "franchise": "18e899f6-dd71-41b7-8c45-5dc0919679ef"
}
Daniel de Zwaan
fuente
0

En el servidor, para serializar / deserializar json en objetos personalizados:

public static string Serialize<T>(T obj)
{
    DataContractJsonSerializer serializer = new DataContractJsonSerializer(obj.GetType());
    MemoryStream ms = new MemoryStream();
    serializer.WriteObject(ms, obj);
    string retVal = Encoding.UTF8.GetString(ms.ToArray());
    return retVal;
}

public static T Deserialize<T>(string json)
{
    T obj = Activator.CreateInstance<T>();
    MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(json));
    DataContractJsonSerializer serializer = new DataContractJsonSerializer(obj.GetType());
    obj = (T)serializer.ReadObject(ms);
    ms.Close();
    return obj;
}
Ioannis Suarez
fuente
0

Tuve el mismo problema. Estaba llamando a la página principal "Guardar" desde la ventana emergente Cerrar. Descubrí que estaba usando ClientIDMode="Static"tanto en la página principal como en la página emergente con la misma identificación de control. Eliminar ClientIDMode="Static"de una de las páginas resolvió el problema.

Mintu Goyal
fuente
0

Aquí dataTpe es "json" entonces, data / reqParam debe estar en forma de cadena mientras se llama a la API, tanto como objeto como desee, pero por fin dentro de los datos de $ .ajax, cadena el objeto.

             let person= {  name: 'john',
                age: 22
            };

           var personStr = JSON.stringify(person); 

            $.ajax({
                url: "@Url.Action("METHOD", "CONTROLLER")",
                type: "POST",
                data: JSON.stringify( { param1: personStr } ),
                contentType: "application/json;charset=utf-8",
                dataType: "json",
        success: function (response) {

            console.log("Success");

        },
        error: function (error) {
            console.log("error found",error);
        }
    });

O,

       $.ajax({
                url: "@Url.Action("METHOD", "CONTROLLER")",
                type: "POST",
                data: personStr,
                contentType: "application/json;charset=utf-8",
                dataType: "json",
        success: function (response) {

            console.log("Success");

        },
        error: function (error) {
            console.log("error found",error);
        }
    });
Gaurav Basnet
fuente
-2

estas respuestas me hicieron rebotar entre el parámetro no válido y el parámetro faltante.

esto funcionó para mí, simplemente envuelva las variables de cadena entre comillas ...

data: { RecordId: RecordId,
            UserId: UId,
            UserProfileId: UserProfileId,
            ItemType: '"' +  ItemType + '"',
            FileName: '"' +  XmlName + '"'
    }
vernmico
fuente