Postar uma matriz de objects via JSON para asp.net MVC3

Eu estou procurando uma solução para POSTing uma matriz de objects para o MVC3 via JSON.

Exemplo de código do qual estou trabalhando: http://weblogs.asp.net/scottgu/archive/2010/07/27/introducing-asp-net-mvc-3-preview-1.aspx

JS:

var data = { ItemList: [ {Str: 'hi', Enabled: true} ], X: 1, Y: 2 }; $.ajax({ url: '/list/save', data: JSON.stringify(data), success: success, error: error, type: 'POST', contentType: 'application/json, charset=utf-8', dataType: 'json' }); 

ListViewModel.cs:

 public class ListViewModel { public List ItemList { get; set; } public float X { get; set; } public float Y { get; set; } } 

ItemViewModel.cs:

 public class ItemViewModel { public string Str; // originally posted with: { get; set; } public bool Enabled; // originally posted with: { get; set; } } 

ListController.cs:

 public ActionResult Save(ListViewModel list) { // Do something } 

O resultado deste POST:

lista está definida, para um ListViewModel
Suas propriedades X e Y estão definidas
A propriedade ItemList subjacente está definida
O ItemList contém um item, como deveria
O item nessa lista de itens é não inicializado. Str é nulo e Enabled é falso.

Dito de outra forma, é isso que recebo da binding de modelo do MVC3:

 list.X == 1 list.Y == 2 list.ItemList != null list.ItemList.Count == 1 list.ItemList[0] != null list.ItemList[0].Str == null 

Parece que o MVC3 JsonValueProvider não está funcionando para objects complexos. Como faço para que isso funcione? Preciso modificar o MVS3 JsonValueProvider existente e corrigi-lo? Se sim, como faço para obtê-lo e substituí-lo em um projeto MVC3?

Perguntas relacionadas ao StackOverflow que já desenvolvi sem sucesso:

Asp.net Mvc Ajax Json (pós Array) Usa MVC2 e codificação baseada em formulário mais antiga – essa abordagem falha com um object que contém uma matriz de objects (o JQuery não consegue codificá-lo corretamente).

Poste uma matriz de objects complexos com JSON, JQuery para o Controlador ASP.NET MVC Usa um hack que eu gostaria de evitar onde o Controller recebe uma string simples que então desserializa manualmente, ao invés de alavancar a estrutura.

MVC3 RC2 JSON Post Binding não está funcionando corretamente Não tem o seu tipo de conteúdo definido – é definido no meu código.

Como postar uma matriz de objects complexos com JSON, jQuery para o controlador ASP.NET MVC? Esse pobre coitado teve que escrever um JsonFilter apenas para analisar um array. Outro truque que prefiro evitar.

Então, como faço isso acontecer?

Além de { get; set; } { get; set; } { get; set; } , estas são algumas das condições para o suporte a JSON Binding:

  1. Esse é um novo recurso da ASP.NET MVC 3 (consulte “ Aprimoramentos em JavaScript e AJAX ”).
  2. As strings do object JSON (‘X’, ‘Y’, ‘Str’ e ‘Enabled’) devem corresponder às propriedades do object ViewModel.
  3. As propriedades do object ViewModel devem ter { get; set; } { get; set; } { get; set; } método.
  4. Deve especificar o tipo de conteúdo como “application / json” na solicitação.
  5. Se ainda não estiver funcionando, verifique a string JSON para certificar-se de que ela é válida.

Leia mais no meu post .

Espero que ajude!

O problema era que as propriedades nos modelos que estavam na Lista não tinham get / set em suas propriedades públicas. Em outras palavras, a binding JSON automática do MVC3 só funciona nas propriedades do object que foram obtidas e configuradas.

Isso não irá ligar:

 public string Str; 

Isso irá ligar:

 public string Str { get; set; } 

Isso é estranho. Eu não consigo reproduzir seu comportamento. Aqui está minha configuração (ASP.NET MVC 3 RTM):

Modelo:

 public class ItemViewModel { public string Str { get; set; } public bool Enabled { get; set; } } public class ListViewModel { public List ItemList { get; set; } public float X { get; set; } public float Y { get; set; } } 

Controlador:

 public class HomeController : Controller { public ActionResult Index() { return View(); } [HttpPost] public ActionResult Save(ListViewModel list) { return Json(list); } } 

Visão:

 @{ ViewBag.Title = "Home Page"; }  

Executando este alerta "hi" e dentro da ação Save tudo está corretamente inicializado.

E apenas para registro, o que não funciona são os Dicionários. Eu abri um ticket sobre o assunto.

Eu tive um problema semelhante e descobri que, para um object complexo, os valores numéricos estavam sendo perdidos. Eles estavam chegando como zeros. ou seja

  var person = { Name: "john", Age: 9 } 

estava sendo recebido pelo controlador MVC como um object Person em que as propriedades estavam sendo preenchidas como Name=John e Age=0 .

Eu então fiz o valor Age em Javascript ser string … ie

  var person = { Name: "john", Age: "9" } 

E isso veio muito bem …

É porque os classificadores MVC são uma droga. No entanto, eles funcionam muito bem se todos os valores JSON vierem como uma string.

No JS, se você fizer isso

 var myObject = {thisNumber:1.6}; myObject.thisNumber=myObject.thisNumber-.6; 

Ele irá avaliar para 1 não para 1.0

Então, quando você o envia para o servidor, ele tentará se ligar a um float com esse nome e não o encontrará, já que ele veio como 1 em vez de 1.0. É muito ruim e maluco que os engenheiros da MS não tenham uma solução padrão para isso. Eu acho que se você encadear tudo, as ligações são inteligentes o suficiente para encontrar coisas.

Portanto, antes de enviar os dados, execute-os através de um string que também converterá todos os valores em strings.

Todas as respostas anteriores foram ótimas para me apontar a solução do problema similar. Eu tive que POST x-www-form-urlencoding vez de application/json (opção padrão se o parâmetro contentType está faltando) para ser capaz de passar __RequestVerificationToken e simultaneamente confrontado com problema quando as propriedades do object que estão na matriz não vinculam seus valores. A maneira de resolver o problema é entender o trabalho interno do fichário do modelo MVC.

Então, basicamente quando você precisa fornecer o token de verificação, você está restrito ao atributo de validação. E você deve fornecer o token como o parâmetro não como parte do object JSON que você está enviando. Se você não usasse o ValidateAntiForgeryToken , poderia se dar bem com o JSON.stringify. Mas se você, você não poderia passar o token.

Chequei o tráfego para o backend quando o ContentType era x-www-form-urlencoding e observei que minha matriz de objects complexos era serializada para algo assim: klo[0][Count]=233&klo[0][Blobs]=94 . Este array inicialmente fazia parte do object raiz, digamos algum modelo. Parecia assim: model.klo = [{ Count: 233, Blobs: 94}, ...] .

No backend esta propriedade klo estava criando por fichário MVC com os mesmos elementos que eu enviei. Mas esses elementos em si não obtiveram valores para suas propriedades.

SOLUÇÃO

Para lidar com isso, excluí a propriedade klo do object de modelo no lado do cliente. Na function ajax , escrevi este código:

 data: $.param(model) + "&" + arrayOfObjectsToFormEncoding("klo", [{ Count: 233, Blobs: 94}, ...]) .... function arrayOfObjectsToFormEncoding (modelPropertyName, arrayOfObjects) { var result = ""; if (arrayOfObjects && typeof arrayOfObjects == "object") { for (var i = 0; i < arrayOfObjects.length; i++) { var obj = arrayOfObjects[i]; if (obj) { for (var p in obj) { if (obj.hasOwnProperty(p)) { result += encodeURIComponent(modelPropertyName + "[" + i + "]." + p) + "=" + encodeURIComponent(obj[p]) + "&"; } } } } } if (result[result.length - 1] == "&") { result = result.substr(0, result.length - 1); } return result; } 

A function transforma a matriz de object complexo em um formulário que é reconhecido pelo MVC-Binder. O formulário é klo[0].Count=233&klo[0].Blobs=94 .