Como posso postar uma matriz de seqüência de caracteres no ASP.NET MVC Controller sem um formulário?

185

Estou criando um pequeno aplicativo para me ensinar o ASP.NET MVC e JQuery, e uma das páginas é uma lista de itens nos quais alguns podem ser selecionados. Gostaria de pressionar um botão e enviar uma lista (ou algo equivalente) ao meu controlador contendo os IDs dos itens que foram selecionados, usando a função Post do JQuery.

Consegui obter uma matriz com os IDs dos elementos que foram selecionados e agora quero publicá-la. Uma maneira de fazer isso é ter um formulário fictício na minha página, com um valor oculto, e depois definir o valor oculto com os itens selecionados, e postar esse formulário; isso parece sujo, no entanto.

Existe uma maneira mais limpa de conseguir isso, enviando a matriz diretamente para o controlador? Eu tentei algumas coisas diferentes, mas parece que o controlador não pode mapear os dados que está recebendo. Aqui está o código até agora:

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

E então meu controlador fica assim

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

Tudo o que consegui obter é um "nulo" no parâmetro do controlador ...

Alguma dica?

rodbv
fonte
Embora, você pode acessar os mesmos dados usandoRequest["values[]"]
Tocco

Respostas:

247

Modifiquei minha resposta para incluir o código de um aplicativo de teste que fiz.

Atualização: atualizei o jQuery para definir a configuração "tradicional" como true, para que funcione novamente (por resposta de @DustinDavis).

Primeiro o 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
    });
}

E aqui está o código na minha classe de controlador:

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

Quando chamo essa função javascript, recebo um alerta dizendo "Primeiro item da lista: 'item1'". Espero que isto ajude!

MrDustpan
fonte
3
É bom que eu encontrei essa resposta, agora posso enviar uma série de Guid's e a Action os recebe para List <Guid>. Obrigado
Tx3 17/05
43
Há duas coisas importantes a serem observadas aqui. 1) dataType: "json" 2.) tradicional: true .Sem a matriz de strings não será passada para os métodos de ação
Thanigainathan
1
Observe que dataType: 'JSON'faz com que o jQuery tente analisar a resposta como JSON, e ocorrerá um erro se não for JSON válido.
sennett
8
@ Thanigainathan the dataType: 'json'é para o tipo de retorno e não é necessário enviar a matriz para Action. contentType: "application/json; charset=utf-8", é esse, mas em alguns casos como esse não é necessário.
Ruchan
1
@emzero usevar postData = { id: 45, [{myClassProp1: 1, myClassProp2: 2}, {}...], anotherParam: "some string" };
Nick M
108

FYI: JQuery mudou a maneira como eles serializam os dados de postagem.

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

Você deve definir a configuração "Tradicional" como verdadeira, caso contrário

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

vai sair como

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

ao invés de

Values=1&Values=2&Values=3
Dustin Davis
fonte
8
Isso é algo que me fez esfregar a cabeça por um tempo. Essa configuração $.ajax({ ..., traditional: true});ajudará a reverter para a serialização tradicional.
31511 juhan_h
Eu precisava disso para que uma rota do ASP.NET MVC consumisse adequadamente uma matriz js simples de valores de string.
precisa
Sua resposta é realmente útil. Eu tenho a mesma situação, mas é com ints. Quando eu uso traditional: true, ele funciona, sua resposta e link explicam o porquê disso. Também funciona quando eu uso type: "POST", sem usar traditional: true. Por que é que? Poderia, por favor, elaborar. Para sua informação, estou usando o Asp.Net Mvc.
barnes
Existe uma maneira no ASP.NET para analisar uma matriz anônima como esta sem índices? Valores [] = 1 & Valores [] = 2 & Valores [] = 3
Charles Owen
24

Obrigado a todos pelas respostas. Outra solução rápida será usar o método jQuery.param com o parâmetro tradicional definido como true para converter o objeto JSON em string:

$.post("/your/url", $.param(yourJsonObject,true));
Evgenii
fonte
Funciona bem e perfeitamente adequado para mim, pois estou usando $ .post () em vez de $ .ajax (). Obrigado !
AFract
6

In .NET4.5,MVC 5

Javascript:

objeto em JS: insira a descrição da imagem aqui

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 recebido:

insira a descrição da imagem aqui

Espero que isso poupe algum tempo.

Matas Vaitkevicius
fonte
4

Outra implementação que também está trabalhando com lista de objetos, não apenas cadeias de caracteres:

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);
    }
});

Supondo que 'selectedValues' seja Array of Objects.

No controlador, o parâmetro é uma lista dos ViewModels correspondentes.

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

Como discuti aqui ,

se você deseja passar o objeto JSON personalizado para a ação MVC, pode usar esta solução, ela funciona como um encanto.

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;
}

O benefício real desta solução é que você não precisa definir uma nova classe para cada combinação de argumentos e, além disso, pode converter seus objetos em seus tipos originais facilmente.

Você pode usar um método auxiliar como este para facilitar seu trabalho:

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
fonte
0

Você pode configurar o parâmetro global com

jQuery.ajaxSettings.traditional = true;
mr_squall
fonte