web-dev-qa-db-fra.com

ASP.NET MVC Comment passer un objet JSON de la vue au contrôleur en tant que paramètre

J'ai un objet JSON complexe qui est envoyé à la vue sans aucun problème (comme indiqué ci-dessous), mais je ne peux pas déterminer comment sérialiser ces données vers un objet .NET lorsqu'elles sont renvoyées au contrôleur via un AJAX Les détails des différentes parties sont ci-dessous.

   var ObjectA = {
        "Name": 1,
        "Starting": new Date(1221644506800),

        "Timeline": [
            {
                "StartTime": new Date(1221644506800),
                "GoesFor": 200

            }
            ,
            {
                "StartTime": new Date(1221644506800),
                "GoesFor": 100

            }

        ]
    };

Je ne sais pas comment cet objet peut être passé à une méthode de contrôleur, j'ai cette méthode ci-dessous où l'objet Timelines reflète l'objet JS ci-dessus en utilisant Propriétés.

public JsonResult Save(Timelines person)

La jQuery que j'utilise est:

        var encoded = $.toJSON(SessionSchedule);

        $.ajax({
            url: "/Timeline/Save",
            type: "POST",
            dataType: 'json',
            data: encoded,
            contentType: "application/json; charset=utf-8",
            beforeSend: function() { $("#saveStatus").html("Saving").show(); },
            success: function(result) {
                alert(result.Result);
                $("#saveStatus").html(result.Result).show();
            }
        });

J'ai vu cette question qui est similaire, mais pas tout à fait la même chose car je n'utilise pas de formulaires pour manipuler les données. Comment passer un type complexe en utilisant json au contrôleur ASP.NET MVC

J'ai également vu des références à l'utilisation d'un 'JsonFilter' pour désérialiser manuellement le JSON, mais je me demandais s'il y avait un moyen de le faire nativement via ASP.NET MVC? Ou quelles sont les meilleures pratiques pour transmettre des données de cette manière?

52
Rosstified

Modifier:

Cette méthode ne devrait plus être nécessaire avec l'arrivée de MVC 3, car elle sera gérée automatiquement - http://weblogs.asp.net/scottgu/archive/2010/07/27/introducing-asp-net -mvc-3-preview-1.aspx


Vous pouvez utiliser ce ObjectFilter:

    public class ObjectFilter : ActionFilterAttribute {

    public string Param { get; set; }
    public Type RootType { get; set; }

    public override void OnActionExecuting(ActionExecutingContext filterContext) {
        if ((filterContext.HttpContext.Request.ContentType ?? string.Empty).Contains("application/json")) {
            object o =
            new DataContractJsonSerializer(RootType).ReadObject(filterContext.HttpContext.Request.InputStream);
            filterContext.ActionParameters[Param] = o;
        }

    }
}

Vous pouvez ensuite l'appliquer à vos méthodes de contrôleur comme suit:

    [ObjectFilter(Param = "postdata", RootType = typeof(ObjectToSerializeTo))]
    public JsonResult ControllerMethod(ObjectToSerializeTo postdata) { ... }

Donc, fondamentalement, si le type de contenu de la publication est "application/json", cela entrera en action et mappera les valeurs à l'objet de type que vous spécifiez.

50
ChadT

Vous dites "je n'utilise pas de formulaires pour manipuler les données". Mais vous faites un POST. Par conséquent, vous utilisez en fait un formulaire, même s'il est vide.

$ .ajax's dataType indique à jQuery quel type le serveur va retourner , pas ce que vous passez. POST ne peut passer qu'un formulaire. JQuery convertira les données en paires clé/valeur et le passera comme une chaîne de requête. À partir des documents:

Données à envoyer au serveur. Il est converti en chaîne de requête, si ce n'est déjà une chaîne. Il est ajouté à l'URL pour les demandes GET. Voir l'option processData pour empêcher ce traitement automatique. L'objet doit être des paires clé/valeur. Si la valeur est un tableau, jQuery sérialise plusieurs valeurs avec la même clé, c'est-à-dire {foo: ["bar1", "bar2"]} devient '& foo = bar1 & foo = bar2'.

Par conséquent:

  1. Vous ne transmettez pas JSON au serveur. Vous passez JSON à jQuery.
  2. La liaison de modèle se produit de la même manière que dans tout autre cas.
12
Craig Stuntz

Une prise différente avec un simple plugin jQuery

Même si les réponses à cette question sont attendues depuis longtemps, mais je publie toujours une bonne solution avec laquelle je suis venu il y a quelque temps et qui rend vraiment simple l'envoi de JSON complexe à Asp.net MVC les actions du contrôleur afin qu'elles soient liées au modèle quels que soient les paramètres de type fort.

Ce plugin prend également en charge les dates , afin qu'elles soient converties en leur homologue DateTime sans problème.

Vous pouvez trouver tous les détails dans mon article de blog où j'examine le problème et fournit le code nécessaire pour y parvenir.

Tout ce que vous avez à faire est d'utiliser ce plugin côté client. Une demande Ajax ressemblerait à ceci:

$.ajax({
    type: "POST",
    url: "SomeURL",
    data: $.toDictionary(yourComplexJSONobject),
    success: function() { ... },
    error: function() { ... }
});

Mais ce n'est qu'une partie de l'ensemble du problème. Nous sommes maintenant en mesure de publier du JSON complexe sur le serveur, mais comme il sera lié au modèle par un type complexe qui peut avoir des attributs de validation sur les propriétés, les choses peuvent échouer à ce stade. J'ai une solution aussi . Ma solution tire parti de la fonctionnalité jQuery Ajax où les résultats peuvent être réussis ou erronés (comme indiqué dans le code supérieur). Ainsi, lorsque la validation échoue, la fonction error est appelée comme elle est censée l'être.

10
Robert Koritnik

Il existe la classe JavaScriptSerializer que vous pouvez également utiliser. Cela vous permettra de désérialiser le json en un objet .NET. Il y a un générique Deserialize<T>, bien que vous ayez besoin que l'objet .NET ait une signature similaire à celle de javascript. De plus, il existe également une méthode DeserializeObject qui crée simplement un object simple. Vous pouvez ensuite utiliser la réflexion pour obtenir les propriétés dont vous avez besoin.

Si votre contrôleur prend un FormCollection et que vous n'avez rien ajouté d'autre au data le json devrait être dans form[0]:

public ActionResult Save(FormCollection forms) {
  string json = forms[0];
  // do your thing here.
}
4
swilliams

Cette réponse est un suivi de la réponse de DaRKoN_ qui utilisait le filtre d'objet:

[ObjectFilter(Param = "postdata", RootType = typeof(ObjectToSerializeTo))]
    public JsonResult ControllerMethod(ObjectToSerializeTo postdata) { ... }

J'avais un problème pour savoir comment envoyer plusieurs paramètres à une méthode d'action et que l'un d'entre eux soit l'objet json et l'autre une chaîne simple. Je suis nouveau sur MVC et j'avais juste oublié que j'avais déjà résolu ce problème avec des vues non ajaxées.

Ce que je ferais si j'avais besoin, disons, de deux objets différents sur une vue. Je créerais une classe ViewModel. Donc, disons que j'avais besoin de l'objet personne et de l'objet adresse, je ferais ce qui suit:

public class SomeViewModel()
{
     public Person Person { get; set; }
     public Address Address { get; set; }
}

Ensuite, je lierais la vue à SomeViewModel. Vous pouvez faire la même chose avec JSON.

[ObjectFilter(Param = "jsonViewModel", RootType = typeof(JsonViewModel))] // Don't forget to add the object filter class in DaRKoN_'s answer.
public JsonResult doJsonStuff(JsonViewModel jsonViewModel)
{
     Person p = jsonViewModel.Person;
     Address a = jsonViewModel.Address;
     // Do stuff
     jsonViewModel.Person = p;
     jsonViewModel.Address = a;
     return Json(jsonViewModel);
}

Ensuite, dans la vue, vous pouvez utiliser un simple appel avec JQuery comme ceci:

var json = { 
    Person: { Name: "John Doe", Sex: "Male", Age: 23 }, 
    Address: { Street: "123 fk st.", City: "Redmond", State: "Washington" }
};

$.ajax({
     url: 'home/doJsonStuff',
     type: 'POST',
     contentType: 'application/json',
     dataType: 'json',
     data: JSON.stringify(json), //You'll need to reference json2.js
     success: function (response)
     {
          var person = response.Person;
          var address = response.Address;
     }
});
2
Chev

en réponse au commentaire de Dan ci-dessus:

J'utilise cette méthode pour implémenter la même chose, mais pour une raison quelconque, je reçois une exception sur la méthode ReadObject: "Expecting element 'root' from namespace '' .. Encountered 'None' with name '', namespace ''. " Des idées pourquoi? - Dan Appleyard 6 avril 10 à 17:57

J'ai eu le même problème (MVC 3 build 3.0.11209.0), et le post ci-dessous l'a résolu pour moi. Fondamentalement, le sérialiseur json essaie de lire un flux qui n'est pas au début, donc repositionner le flux à 0 le 'fixe' ...

http://nali.org/asp-net-mvc-expecting-element-root-from-namespace-encountered-none-with-name-namespace/

1
user715852