“Primitivo JSON inválido” no processamento Ajax

101

Estou recebendo um erro em uma chamada ajax do jQuery.

Aqui está minha função 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");
        }
    });
}

e este é o meu 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";
}

Alguém pode me dizer o que há de errado no meu código?

Estou recebendo este erro:

{
    "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
fonte
O que eu não entendo é. O javascript é sobre AddAlbumToMyProfile, enquanto o WebMethod é chamado DeleteRecord. Tem certeza de que nos mostra os trechos de código certos?
tremulação de
Alguma chance de você também capturar a aparência do POST (usando firebug ou outros enfeites) e adicioná-lo à pergunta? Não tenho certeza se é a maneira como você está codificando os dados antes de enviá-los, mas você também pode tentar serializá-los usando isso ( json.org/json2.js ).
R0MANARMY

Respostas:

136

Adivinhe o que a variável jsoncontém depois

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

Se for um objeto json válido como o {'foo':'foovalue', 'bar':'barvalue'}jQuery pode não enviá-lo como dados json, mas sim serializá-lo para foor=foovalue&bar=barvalueobter o erro"Invalid JSON primitive: foo"

Em vez disso, tente definir os dados como string

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

Desta forma, o jQuery deve deixar os dados sozinhos e enviar a string como está para o servidor, o que deve permitir que o ASP.NET analise o lado do servidor json.

tremor
fonte
5
obrigado pelo esclarecimento, adicione mais um comentário, você sempre pode fazer como JSON.stringify ({foo: 'foovalue', bar: 'barvalue'}) para uma vida mais fácil
Elaine
Uma década atrasado para a festa, mas ainda relevante: isso não é JSON válido. Strings (incluindo nomes de propriedades) em JSON devem usar aspas duplas , portanto, deveria ser {"foo": "foovalue", "bar": "barvalue"}. Usar aspas simples é um erro de sintaxe.
Mike 'Pomax' Kamermans
108

Usando

data : JSON.stringify(obj)

na situação acima teria funcionado, eu acredito.

Observação: você deve adicionar a biblioteca json2.js, todos os navegadores não suportam esse objeto JSON (IE7-). Diferença entre json.js e json2.js

Andrew
fonte
3
Obrigado! Ao usar classes JS simples, isso funciona. Eu mudei data: { JSON.stringify(obj) }a data: JSON.stringify(obj)(My javascript / JSON classe para serialize é do estilo var myObj = { title: "x", subclass = someVar, ... } )
LKO
1
Observe que esta é a solução fornecida de que você realmente precisa enviar JSON (o que pode ser feito com os serviços da web asp.net ). Em outros casos, pode ser mais fácil apenas remover ocontentType e deixar o jQuery passar os dados codificados pelo formulário.
GSerg
19

Conforme observado pelo jitter, a $.ajaxfunção serializa qualquer objeto / array usado como odata parâmetro em um formato codificado por url. Curiosamente, o dataTypeparâmetro só se aplica à resposta do servidor - e não a quaisquer dados na solicitação.

Depois de encontrar o mesmo problema, baixei e usei o plugin jquery-json para codificar corretamente os dados da solicitação para o ScriptService. Em seguida, use a $.toJSONfunção para codificar os argumentos desejados para enviar ao servidor:

$.ajax({
    type: "POST",
    url: "EditUserProfile.aspx/DeleteRecord",
    data: $.toJSON(obj),
    contentType: "application/json; charset=utf-8",
    dataType: "json"
    ....
});
leepowers
fonte
2
obrigado por apontar que o dataparâmetro é ignorado pela chamada.
Noel Abrahams,
3
Isso funciona, mas mudar data: { JSON.stringify(obj) }para data: JSON.stringify(obj)funcionou para mim se a sua classe javascript é do estilo var myObj = { title: "x", subclass = someVar, ... } graças ao ponto sobre a codificação de dados.
lko
19

está funcionando algo assim

data: JSON.stringify({'id':x}),
Jessica Saenz
fonte
3
Essa resposta apareceu na fila de revisão de baixa qualidade, provavelmente porque você não forneceu nenhuma explicação sobre o código. Se este código responder à pergunta, considere adicionar algum texto explicando o código em sua resposta. Dessa forma, é muito mais provável que você obtenha mais votos positivos - e ajude o questionador a aprender algo novo.
lmo
Eu quero passar dois parâmetros: uma matriz de objeto complexo e um inteiro. Eu faço isso: data: {items: JSON.stringify (myarray), myId: value}.
A.Dara
13

O Jquery Ajax enviará por padrão os dados como parâmetros de string de consulta como:

RecordId=456&UserId=123

a menos que a processDataopção seja definida como falsa, caso em que será enviada como objeto ao servidor.

  • contentType a opção é para o servidor em que formato o cliente enviou os dados.

  • dataType opção é para o servidor que informa que tipo de cliente de dados está esperando de volta do servidor.

Não especifique contentType para que o servidor os analise como parâmetros de string de consulta, não como json.

OU

Use contentType como 'application / json; charset = utf-8 'e use JSON.stringify (objeto) para que o servidor seja capaz de desserializar json da string.

T Gupta
fonte
5

Acho que @jitter estava certo em seu palpite, mas sua solução não funcionou para mim.

Aqui está o que funcionou:

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

Eu não tentei, mas acho que se o parâmetro é uma string, deveria ser assim:

$.ajax({
    ...
    data: "{ intFoo: " + intFoo + ", strBar: '" + strBar + "' }",
    ...
});
Diego
fonte
9
Se eu tivesse que escrever um código assim (string concat) para criar objetos JSON, eu me mataria (falando figurativamente). Tem que haver uma maneira melhor.
PandaWood de
3

Eu estava enfrentando o mesmo problema, o que eu vim com uma boa solução é o seguinte:

Experimente isso ...

$.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");
    }
});

Observe aqui para o parâmetro de tipo de string que usei (\ ') o caractere de sequência de escape para denotá-lo como um valor de string.

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

Se você formatar JSON manualmente, há um validador muito útil aqui: jsonlint.com

Use aspas duplas em vez de aspas 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
fonte
0

No servidor, para serializar / desserializar json para 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
fonte
0

Eu tive o mesmo problema. Eu estava chamando a página principal de "Salvar" em Fechar a janela pop-up. Descobri que estava usando ClientIDMode="Static"na página pai e na página pop-up com a mesma id de controle. Remover ClientIDMode="Static"de uma das páginas resolveu o problema.

Mintu Goyal
fonte
0

Aqui, dataTpe é "json", portanto, data / reqParam deve estar na forma de string ao chamar a API, tanto quanto o objeto que você quiser, mas, finalmente, dentro dos dados de $ .ajax, string o 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);
        }
    });

OU,

       $.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
fonte
-2

essas respostas apenas me fizeram saltar para frente e para trás entre o parâmetro inválido e o parâmetro ausente.

isso funcionou para mim, basta envolver as variáveis ​​de string entre aspas ...

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