Publica una matriz de objetos a través de JSON para ASP.Net MVC3

Estoy buscando una solución para POSTING una matriz de objetos a MVC3 a través de JSON.

Código de ejemplo con el que estoy trabajando: 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 } 

El resultado de este POST:

lista está establecida, en un ListViewModel
Sus propiedades X e Y están establecidas
La propiedad subyacente Lista de elementos se establece
La Lista de elementos contiene un elemento, como debería
El elemento en esa Lista de elementos no está inicializado. Str es nulo y Enabled es falso.

Dicho de otra manera, esto es lo que obtengo del enlace modelo de 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 MVC3 JsonValueProvider no funciona para objetos complejos. ¿Cómo hago que esto funcione? ¿Debo modificar el MVC3 JsonValueProvider existente y corregirlo? Si es así, ¿cómo lo hago y lo reemplazo en un proyecto MVC3?

Preguntas relacionadas con StackOverflow que ya he intentado sin éxito:

Asp.net Mvc Ajax Json (matriz posterior) Utiliza MVC2 y una encoding basada en formularios más antigua: ese enfoque falla con un objeto que contiene una matriz de objetos (JQuery no puede codificarlo correctamente).

Publicar una matriz de objetos complejos con JSON, JQuery para ASP.NET Controlador MVC Utiliza un truco que me gustaría evitar donde el Controlador recibe una cadena simple que luego se deserializa manualmente, en lugar de aprovechar el marco.

MVC3 RC2 JSON Post Binding no funciona correctamente. No tiene su conjunto de tipo de contenido; está configurado en mi código.

¿Cómo publicar una matriz de objetos complejos con JSON, jQuery a ASP.NET MVC Controller? Este pobre tipo tuvo que escribir un JsonFilter solo para analizar un conjunto. Otro truco que preferiría evitar.

Entonces, ¿cómo hago que esto suceda?

Además de { get; set; } { get; set; } { get; set; } , estas son algunas de las condiciones para el soporte de enlace JSON:

  1. Esta es una nueva característica en ASP.NET MVC 3 (Ver ” Mejoras de JavaScript y AJAX “).
  2. Las cadenas del objeto JSON (‘X’, ‘Y’, ‘Str’ y ‘Enabled’) deben coincidir con las propiedades del objeto ViewModel.
  3. Las propiedades del objeto ViewModel deben tener { get; set; } { get; set; } { get; set; } método.
  4. Debe especificar Tipo de contenido como “aplicación / json” en la solicitud.
  5. Si aún no funciona, verifique la cadena JSON para asegurarse de que sea válida.

Lea más en mi publicación .

¡Espero que ayude!

El problema era que las propiedades en los modelos que estaban en la Lista no tenían get / set en sus propiedades públicas. Dicho de otra manera, el enlace JSON automático de MVC3 solo funciona en las propiedades de los objetos que tienen get y set.

Esto no obligará:

 public string Str; 

Esto enlazará:

 public string Str { get; set; } 

Eso es extraño. No puedo reproducir tu comportamiento. Aquí está mi configuración (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); } } 

Ver:

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

Ejecutando esta alerta "hi" y dentro de la acción Save , todo se inicializó correctamente.

Y solo para que quede registrado lo que no funciona son los Diccionarios. He abierto un boleto sobre el problema.

Tuve un problema similar y descubrí que para un objeto complejo, los valores numéricos se estaban perdiendo. Entraron como ceros. es decir

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

estaba siendo recibido por el controlador MVC como un objeto Persona donde las propiedades se estaban poblando como Name=John y Age=0 .

Luego hice que el valor de edad en Javascript fuera cadena … es decir,

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

Y esto salió bien …

Es porque las carpetas MVC tipo de chupar. Sin embargo, funcionan bastante bien si todos los valores JSON aparecen como una cadena.

En JS si haces esto

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

Evaluará a 1, no a 1.0

Entonces, cuando lo envíe al servidor, intentará enlazarse con un flotador de ese nombre y no lo encontrará, ya que se convirtió en 1 en lugar de 1.0. Es muy cobarde y loco que los ingenieros de MS no hayan encontrado una solución predeterminada para esto. Me parece que si encierras todo, las ataduras son lo suficientemente inteligentes como para encontrar cosas.

Por lo tanto, antes de enviar los datos a través de la ejecución, utilice un secuenciador que también convertirá todos los valores en cadenas.

Todas las respuestas anteriores fueron excelentes para indicarme la solución del problema similar. Tuve que PUBLICAR x-www-form-urlencoding lugar de application/json (opción predeterminada si falta el parámetro contentType) para poder pasar __RequestVerificationToken y enfrentar simultáneamente un problema cuando las propiedades de los objetos que están en la matriz no vinculan sus valores. La forma de resolver el problema es comprender el trabajo interno de la carpeta de modelos de MVC.

Entonces, básicamente, cuando necesita suministrar el token de verificación, se le restringe el atributo de validación. Y debe proporcionar el token como parámetro no como parte del objeto JSON que está enviando. Si no usa ValidateAntiForgeryToken , podría llevarse bien con JSON.stringify. Pero si lo hicieras, no podrías pasar la ficha.

Me olí el tráfico al backend cuando ContentType era x-www-form-urlencoding y observé que mi matriz de objetos complejos se serializaba a algo así: klo[0][Count]=233&klo[0][Blobs]=94 . Esta matriz inicialmente formaba parte del objeto raíz, digamos un modelo. Se veía así: model.klo = [{ Count: 233, Blobs: 94}, ...] .

En el lado de back-end, esta propiedad de klo estaba creando por medio de la carpeta MVC con los mismos elementos que yo envié. Pero estos elementos en sí no obtuvieron valores para sus propiedades.

SOLUCIÓN

Para tratar con esto, klo propiedad klo del objeto modelo en el lado del cliente. En la función ajax escribí 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; } 

La función transforma matriz de objeto complejo en forma reconocida por MVC-Binder. La forma es klo[0].Count=233&klo[0].Blobs=94 .