Comment puis-je publier un tableau de chaînes sur le contrôleur ASP.NET MVC sans formulaire?

185

Je crée une petite application pour m'enseigner ASP.NET MVC et JQuery, et l'une des pages est une liste d'éléments dans lesquels certains peuvent être sélectionnés. Ensuite, je voudrais appuyer sur un bouton et envoyer une liste (ou quelque chose d'équivalent) à mon contrôleur contenant les identifiants des éléments qui ont été sélectionnés, en utilisant la fonction Post de JQuery.

J'ai réussi à obtenir un tableau avec les identifiants des éléments sélectionnés, et maintenant je veux le publier. Une façon de le faire est d'avoir un formulaire factice dans ma page, avec une valeur masquée, puis de définir la valeur masquée avec les éléments sélectionnés et de publier ce formulaire; cela semble cruel, cependant.

Existe-t-il un moyen plus propre d'y parvenir, en envoyant le tableau directement au contrôleur? J'ai essayé différentes choses, mais il semble que le contrôleur ne puisse pas mapper les données qu'il reçoit. Voici le code jusqu'à présent:

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

Et puis ma manette ressemble à ça

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

Tout ce que j'ai réussi à obtenir est un "null" dans le paramètre du contrôleur ...

Des conseils?

rodbv
la source
Bien que vous puissiez accéder aux mêmes données en utilisantRequest["values[]"]
Tocco

Réponses:

247

J'ai modifié ma réponse pour inclure le code d'une application de test que j'ai faite.

Mise à jour: J'ai mis à jour jQuery pour définir le paramètre «traditionnel» sur true afin que cela fonctionne à nouveau (par réponse de @DustinDavis).

Tout d'abord le 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
    });
}

Et voici le code dans ma classe de contrôleur:

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

Quand j'appelle cette fonction javascript, j'obtiens une alerte disant "Premier élément de la liste: 'item1'". J'espère que cela t'aides!

MrDustpan
la source
3
C'est bien que j'ai trouvé cette réponse, maintenant je peux envoyer un tableau de Guid et Action les reçoit à List <Guid>. Merci
Tx3
43
Il y a deux choses importantes à noter ici. 1) dataType: "json" 2.) Traditional: true .Sans eux, le tableau de chaînes ne sera pas passé aux méthodes d'action
Thanigainathan
1
Notez que dataType: 'JSON'jQuery tente d'analyser la réponse en tant que JSON et génère une erreur si ce n'est pas un JSON valide.
sennett
8
@Thanigainathan dataType: 'json'est pour le type de retour et n'est pas obligé d'envoyer le tableau à Action. contentType: "application/json; charset=utf-8", est celui-ci, mais dans certains cas, ce n'est pas obligatoire.
Ruchan
1
@emzero usevar postData = { id: 45, [{myClassProp1: 1, myClassProp2: 2}, {}...], anotherParam: "some string" };
Nick M
108

FYI: JQuery a changé la façon dont ils sérialisent les données de publication.

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

Vous devez définir le paramètre `` Traditionnel '' sur vrai, sinon

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

sortira comme

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

au lieu de

Values=1&Values=2&Values=3
Dustin Davis
la source
8
C'est quelque chose qui m'a fait me gratter la tête pendant un moment. Le réglage $.ajax({ ..., traditional: true});aidera à revenir à la sérialisation traditionnelle.
juhan_h
J'en avais besoin pour qu'une route ASP.NET MVC consomme correctement un simple tableau js de valeurs de chaîne.
BrandonG
Votre réponse est vraiment utile. J'ai la même situation mais c'est avec ints. Quand j'utilise traditional: true, ça marche, votre réponse et votre lien expliquent pourquoi . Cela fonctionne également lorsque j'utilise type: "POST", sans utiliser traditional: true. Pourquoi donc? Pourriez-vous s'il vous plaît élaborer. Pour info, j'utilise Asp.Net Mvc.
barnes
Existe-t-il un moyen dans ASP.NET d'analyser un tableau anonyme comme celui-ci sans index? Values ​​[] = 1 & Values ​​[] = 2 & Values ​​[] = 3
Charles Owen
24

Merci à tous pour les réponses. Une autre solution rapide sera d'utiliser la méthode jQuery.param avec le paramètre traditionnel défini sur true pour convertir l'objet JSON en chaîne:

$.post("/your/url", $.param(yourJsonObject,true));
Evgenii
la source
Fonctionne bien et parfaitement adapté pour moi car j'utilise $ .post () au lieu de $ .ajax (). Je vous remercie !
AFract
9

Ne publiez pas les données sous forme de tableau. Pour se lier à une liste, les paires clé / valeur doivent être soumises avec la même valeur pour chaque clé.

Vous ne devriez pas avoir besoin d'un formulaire pour ce faire. Vous avez juste besoin d'une liste de paires clé / valeur, que vous pouvez inclure dans l'appel à $ .post.

Craig Stuntz
la source
3
Merci. L'URL mise à jour est: haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
Wiebe Tijsma
6

Dans .NET4.5,MVC 5

Javascript:

objet dans JS: entrez la description de l'image ici

mécanisme qui affiche.

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

C #

Objets:

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

Manette:

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

Objet reçu:

entrez la description de l'image ici

J'espère que cela vous fera gagner du temps.

Matas Vaitkevicius
la source
4

Une autre implémentation qui fonctionne également avec une liste d'objets, pas seulement des chaînes:

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

En supposant que «selectedValues» est un tableau d'objets.

Dans le contrôleur, le paramètre est une liste de ViewModels correspondants.

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

Comme je l'ai discuté ici ,

si vous voulez passer un objet JSON personnalisé à l'action MVC, vous pouvez utiliser cette solution, cela fonctionne comme un charme.

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

Le véritable avantage de cette solution est que vous n'avez pas besoin de définir une nouvelle classe pour chaque combinaison d'arguments et à côté de cela, vous pouvez convertir facilement vos objets dans leurs types d'origine.

Vous pouvez utiliser une méthode d'aide comme celle-ci pour faciliter votre travail:

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
la source
0

Vous pouvez configurer le paramètre global avec

jQuery.ajaxSettings.traditional = true;
mr_squall
la source