¿Cómo puedo publicar una matriz de cadenas en el controlador ASP.NET MVC sin un formulario?

185

Estoy creando una pequeña aplicación para enseñarme ASP.NET MVC y JQuery, y una de las páginas es una lista de elementos en los que se pueden seleccionar algunos. Luego me gustaría presionar un botón y enviar una Lista (o algo equivalente) a mi controlador que contenga los identificadores de los elementos seleccionados, utilizando la función Publicar de JQuery.

Logré obtener una matriz con los identificadores de los elementos que fueron seleccionados, y ahora quiero publicar eso. Una forma de hacerlo es tener un formulario ficticio en mi página, con un valor oculto, y luego establecer el valor oculto con los elementos seleccionados y publicar ese formulario; Sin embargo, esto se ve mal.

¿Hay una forma más limpia de lograr esto, enviando la matriz directamente al controlador? He intentado algunas cosas diferentes, pero parece que el controlador no puede asignar los datos que está recibiendo. Aquí está el código hasta ahora:

function generateList(selectedValues) {
   var s = {
      values: selectedValues //selectedValues is an array of string
   };
   $.post("/Home/GenerateList", $.toJSON(s), function() { alert("back") }, "json");
}

Y entonces mi controlador se ve así

public ActionResult GenerateList(List<string> values)
{
    //do something
}

Todo lo que pude obtener es un "nulo" en el parámetro del controlador ...

¿Algun consejo?

rodbv
fuente
Sin embargo, puede acceder a los mismos datos utilizandoRequest["values[]"]
Tocco

Respuestas:

247

Modifiqué mi respuesta para incluir el código de una aplicación de prueba que hice.

Actualización: He actualizado jQuery para establecer la configuración 'tradicional' en verdadero para que esto funcione nuevamente (según la respuesta de @DustinDavis).

Primero el javascript:

function test()
{
    var stringArray = new Array();
    stringArray[0] = "item1";
    stringArray[1] = "item2";
    stringArray[2] = "item3";
    var postData = { values: stringArray };

    $.ajax({
        type: "POST",
        url: "/Home/SaveList",
        data: postData,
        success: function(data){
            alert(data.Result);
        },
        dataType: "json",
        traditional: true
    });
}

Y aquí está el código en mi clase de controlador:

public JsonResult SaveList(List<String> values)
{
    return Json(new { Result = String.Format("Fist item in list: '{0}'", values[0]) });
}

Cuando llamo a esa función de JavaScript, recibo una alerta que dice "Primer elemento de la lista: 'elemento1'". ¡Espero que esto ayude!

MrDustpan
fuente
3
Es bueno que haya encontrado esta respuesta, ahora puedo enviar un conjunto de Guid y Action los recibe a List <Guid>. Gracias
Tx3
43
Hay dos cosas importantes a tener en cuenta aquí. 1) dataType: "json" 2.) Tradicional: verdadero. Sin ellos, el conjunto de cadenas no se
pasará
1
Tenga en cuenta que dataType: 'JSON'hace que jQuery intente analizar la respuesta como JSON y generará un error si no es JSON válido.
sennett
8
@Thanigainathan dataType: 'json'es para el tipo de retorno y no es necesario para enviar la matriz a Action. contentType: "application/json; charset=utf-8", es el indicado, pero en algunos casos como este no es obligatorio.
Ruchan
1
@emzero usevar postData = { id: 45, [{myClassProp1: 1, myClassProp2: 2}, {}...], anotherParam: "some string" };
Nick M
108

FYI: JQuery cambió la forma en que serializan los datos de la publicación.

http://forum.jquery.com/topic/nested-param-serialization

Debe establecer la configuración 'Tradicional' en verdadero, de lo contrario

{ Values : ["1", "2", "3"] }

saldrá como

Values[]=1&Values[]=2&Values[]=3

en vez de

Values=1&Values=2&Values=3
Dustin Davis
fuente
8
Esto es algo que me hizo rasparme la cabeza por un tiempo. la configuración $.ajax({ ..., traditional: true});ayudará a volver a la serialización tradicional.
juhan_h
Necesitaba esto para que una ruta ASP.NET MVC consumiera correctamente una simple matriz js de valores de cadena.
BrandonG
Tu respuesta es realmente útil. Tengo la misma situación pero es con ints. Cuando lo uso traditional: true, funciona, su respuesta y enlace explican por qué . También funciona cuando lo uso type: "POST", sin usar traditional: true. ¿Porqué es eso? ¿Podría por favor dar más detalles? FYI estoy usando Asp.Net Mvc.
Barnes
¿Hay alguna manera en ASP.NET de analizar una matriz anónima como esta sin índices? Valores [] = 1 y Valores [] = 2 y Valores [] = 3
Charles Owen
24

Gracias a todos por las respuestas. Otra solución rápida será usar el método jQuery.param con el parámetro tradicional establecido en verdadero para convertir el objeto JSON en una cadena:

$.post("/your/url", $.param(yourJsonObject,true));
Evgenii
fuente
Funciona bien y me queda perfectamente, ya que estoy usando $ .post () en lugar de $ .ajax (). Gracias !
AFract
6

en .NET4.5,MVC 5

Javascript:

objeto en JS: ingrese la descripción de la imagen aquí

mecanismo que publica.

    $('.button-green-large').click(function() {
        $.ajax({
            url: 'Quote',
            type: "POST",
            dataType: "json",
            data: JSON.stringify(document.selectedProduct),
            contentType: 'application/json; charset=utf-8',
        });
    });

C#

Objetos:

public class WillsQuoteViewModel
{
    public string Product { get; set; }

    public List<ClaimedFee> ClaimedFees { get; set; }
}

public partial class ClaimedFee //Generated by EF6
{
    public long Id { get; set; }
    public long JourneyId { get; set; }
    public string Title { get; set; }
    public decimal Net { get; set; }
    public decimal Vat { get; set; }
    public string Type { get; set; }

    public virtual Journey Journey { get; set; }
}

Controlador:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Quote(WillsQuoteViewModel data)
{
....
}

Objeto recibido:

ingrese la descripción de la imagen aquí

Espero que esto te ahorre algo de tiempo.

Matas Vaitkevicius
fuente
4

Otra implementación que también funciona con una lista de objetos, no solo cadenas:

JS:

var postData = {};
postData[values] = selectedValues ;

$.ajax({
    url: "/Home/SaveList",
    type: "POST",
    data: JSON.stringify(postData),
    dataType: "json",
    contentType: "application/json; charset=utf-8",
    success: function(data){
        alert(data.Result);
    }
});

Asumiendo que 'selectedValues' es Array of Objects.

En el controlador, el parámetro es una lista de ViewModels correspondientes.

public JsonResult SaveList(List<ViewModel> values)
{    
    return Json(new { 
          Result = String.Format("Fist item in list: '{0}'", values[0].Name) 
    });
}
d.popov
fuente
1

Como discutí aquí ,

si desea pasar un objeto JSON personalizado a la acción MVC, puede usar esta solución, funciona de maravilla.

public string GetData() {
  // InputStream contains the JSON object you've sent
  String jsonString = new StreamReader(this.Request.InputStream).ReadToEnd();

  // Deserialize it to a dictionary
  var dic =
    Newtonsoft.Json.JsonConvert.DeserializeObject < Dictionary < String,
    dynamic >> (jsonString);

  string result = "";

  result += dic["firstname"] + dic["lastname"];

  // You can even cast your object to their original type because of 'dynamic' keyword
  result += ", Age: " + (int) dic["age"];

  if ((bool) dic["married"])
    result += ", Married";

  return result;
}

El beneficio real de esta solución es que no necesita definir una nueva clase para cada combinación de argumentos y, además, puede convertir sus objetos a sus tipos originales fácilmente.

Puede utilizar un método auxiliar como este para facilitar su trabajo:

public static Dictionary < string, dynamic > GetDic(HttpRequestBase request) {
  String jsonString = new StreamReader(request.InputStream).ReadToEnd();
  return Newtonsoft.Json.JsonConvert.DeserializeObject < Dictionary < string, dynamic >> (jsonString);
}
Mohsen Afshin
fuente
0

Puede configurar el parámetro global con

jQuery.ajaxSettings.traditional = true;
mr_squall
fuente