Bonne façon d'utiliser AJAX Post dans jquery pour passer le modèle à partir d'une vue MVC3 fortement typée

101

Je suis un programmeur web novice alors pardonnez-moi si une partie de mon "jargon" n'est pas correcte. J'ai un projet utilisant ASP.NET utilisant le framework MVC3.

Je travaille sur une vue d'administration où l'administrateur modifiera une liste d'équipements. Une des fonctions est un bouton "mise à jour" que je souhaite utiliser jquery pour éditer dynamiquement l'entrée sur la page Web après l'envoi d'un message au contrôleur MVC.

Je présume que cette approche est «sûre» dans un seul cadre d'administration où il y a un problème minimal de désynchronisation de la page Web avec la base de données.

J'ai créé une vue fortement typée et j'espérais transmettre les données du modèle au contrôle MVC à l'aide d'une publication AJAX.

Dans le post suivant, j'ai trouvé quelque chose qui est similaire à ce que je cherche à faire: JQuery Ajax et ASP.NET MVC3 provoquant des paramètres nuls

J'utiliserai l'exemple de code de l'article ci-dessus.

Modèle:

public class AddressInfo 
{
    public string Address1 { get; set; }
    public string Address2 { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string ZipCode { get; set; }
    public string Country { get; set; }
}

Manette:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View();
    }

    [HttpPost]
    public ActionResult Check(AddressInfo addressInfo)
    {
        return Json(new { success = true });
    }
}

script dans View:

<script type="text/javascript">
var ai = {
    Address1: "423 Judy Road",
    Address2: "1001",
    City: "New York",
    State: "NY",
    ZipCode: "10301",
    Country: "USA"
};

$.ajax({
    url: '/home/check',
    type: 'POST',
    data: JSON.stringify(ai),
    contentType: 'application/json; charset=utf-8',
    success: function (data.success) {
        alert(data);
    },
    error: function () {
        alert("error");
    }
});
</script>

Je n'ai pas encore eu l'occasion d'utiliser ce qui précède. Mais je me demandais si c'était la «meilleure» méthode pour renvoyer les données du modèle au contrôle MVC en utilisant AJAX?

Dois-je être préoccupé par la divulgation des informations du modèle?

John Stone
la source

Réponses:

72

Vous pouvez ignorer la déclaration var et le stringify. Sinon, cela fonctionnera très bien.

$.ajax({
    url: '/home/check',
    type: 'POST',
    data: {
        Address1: "423 Judy Road",
        Address2: "1001",
        City: "New York",
        State: "NY",
        ZipCode: "10301",
        Country: "USA"
    },
    contentType: 'application/json; charset=utf-8',
    success: function (data) {
        alert(data.success);
    },
    error: function () {
        alert("error");
    }
});
Craig M
la source
Merci d'avoir signalé le léger ajustement. Y a-t-il un problème à exposer la structure du modèle du point de vue de la sécurité?
John Stone
Rien de flagrant ne me semble être un problème de sécurité. Si cela vous préoccupe vraiment, vous pouvez toujours créer un classeur de modèle personnalisé du côté mvc.
Craig M
8
Cela a échoué pour moi. J'ai dû utiliser JSON.stringify ({...}) pour que l'appel fonctionne dans MVC5.
Johncl du
J'ai remarqué que je devais faire de même lorsque je travaillais avec des contrôleurs API. Cette réponse a cependant été écrite il y a 4 ans, avant que les contrôleurs d'API n'existent.
Craig M
1
putain de merde, j'ai eu dataType au lieu de contentType, celui-là me comprend toujours !!
Phil
175

J'ai trouvé 3 façons de mettre en œuvre cela:

Classe C #:

public class AddressInfo {
    public string Address1 { get; set; }
    public string Address2 { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string ZipCode { get; set; }
    public string Country { get; set; }
}

Action:

[HttpPost]
public ActionResult Check(AddressInfo addressInfo)
{
    return Json(new { success = true });
}

JavaScript, vous pouvez le faire de trois manières:

1) Chaîne de requête:

$.ajax({
    url: '/en/Home/Check',
    data: $('#form').serialize(),
    type: 'POST',
});

Les données ici sont une chaîne.

"Address1=blah&Address2=blah&City=blah&State=blah&ZipCode=blah&Country=blah"

2) Tableau d'objets:

$.ajax({
    url: '/en/Home/Check',
    data: $('#form').serializeArray(),
    type: 'POST',
});

Les données ici sont un tableau de paires clé / valeur:

=[{name: 'Address1', value: 'blah'}, {name: 'Address2', value: 'blah'}, {name: 'City', value: 'blah'}, {name: 'State', value: 'blah'}, {name: 'ZipCode', value: 'blah'}, {name: 'Country', value: 'blah'}]

3) JSON:

$.ajax({
      url: '/en/Home/Check',
      data: JSON.stringify({ addressInfo:{//missing brackets
          Address1: $('#address1').val(),
          Address2: $('#address2').val(),
          City: $('#City').val(),
          State: $('#State').val(),
          ZipCode: $('#ZipCode').val()}}),
      type: 'POST',
      contentType: 'application/json; charset=utf-8'
});

Les données ici sont une chaîne JSON sérialisée. Notez que le nom doit correspondre au nom du paramètre dans le serveur !!

='{"addressInfo":{"Address1":"blah","Address2":"blah","City":"blah","State":"blah", "ZipCode", "blah", "Country", "blah"}}'
Jazaret
la source
1
Je viens de trouver cette excellente réponse approfondie qui a résolu des questions que je ne savais pas encore. +1, merci!
SeanKilleen
Le n ° 2 était ce que je cherchais. Cela devrait être la réponse.
TheGeekZn
EDIT: dû utiliser data: $('input, textarea, select').serialize(),pour que le mien fonctionne.
TheGeekZn
Salut Jazaret !! comment passer la date au modèle avec la 3ème approche ??
Guruprasad Rao
1
Désolé pour le retard @GuruprasadRao Pour passer une date, vous pouvez avoir la date et l'heure sous forme de chaîne dans le code javascript et MVC la traduira en un objet DateTime.
Jazaret
12

Voici comment cela a fonctionné pour moi:

$.post("/Controller/Action", $("#form").serialize(), function(json) {       
        // handle response
}, "json");

[HttpPost]
public ActionResult TV(MyModel id)
{
    return Json(new { success = true });
}
Sanchitos
la source
8

ce que vous avez est très bien - cependant pour enregistrer un peu de frappe, vous pouvez simplement utiliser pour vos données

données: $ ('# formId'). serialize ()

voir http://www.ryancoughlin.com/2009/05/04/how-to-use-jquery-to-serialize-ajax-forms/ pour plus de détails, la syntaxe est assez basique.

Adam Tuliper - MSFT
la source
Pour utiliser la fonction de sérialisation, je crois comprendre que chaque membre de la classe doit être utilisé dans un objet de formulaire. Si c'est exact, je suis peut-être SOL.
John Stone
1
ah ya .. sinon vous ne pouvez pas utiliser sérialiser alors. vous pouvez toujours manipuler le DOM et créer un formulaire avec ces éléments et le sérialiser - mais ... il serait probablement plus simple de simplement saisir manuellement les champs.
Adam Tuliper - MSFT
@TahaRehmanSiddiqui serialize fonctionne en effet dans IE, qu'est-ce qui ne fonctionne pas? Avez-vous une erreur?
Adam Tuliper - MSFT
chaque propriété de mon modèle sort null
Taha Rehman Siddiqui
@TahaRehmanSiddiqui est-ce que le «nom» de vos champs de formulaire correspond aux noms de vos propriétés de modèle?
MongooseNX
0

Si vous utilisez MVC 5, lisez cette solution!

Je connais la question spécifiquement appelée pour MVC 3, mais je suis tombé sur cette page avec MVC 5 et je voulais publier une solution pour quiconque dans ma situation. J'ai essayé les solutions ci-dessus, mais elles n'ont pas fonctionné pour moi, le filtre d'action n'a jamais été atteint et je ne pouvais pas comprendre pourquoi. J'utilise la version 5 dans mon projet et j'ai fini avec le filtre d'action suivant:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Filters;

namespace SydHeller.Filters
{
    public class ValidateJSONAntiForgeryHeader : FilterAttribute, IAuthorizationFilter
    {
        public void OnAuthorization(AuthorizationContext filterContext)
        {
            string clientToken = filterContext.RequestContext.HttpContext.Request.Headers.Get(KEY_NAME);
            if (clientToken == null)
            {
                throw new HttpAntiForgeryException(string.Format("Header does not contain {0}", KEY_NAME));
            }

            string serverToken = filterContext.HttpContext.Request.Cookies.Get(KEY_NAME).Value;
            if (serverToken == null)
            {
                throw new HttpAntiForgeryException(string.Format("Cookies does not contain {0}", KEY_NAME));
            }

            System.Web.Helpers.AntiForgery.Validate(serverToken, clientToken);
        }

        private const string KEY_NAME = "__RequestVerificationToken";
    }
}

- Prenez note du using System.Web.Mvcet using System.Web.Mvc.Filters, pas des httpbibliothèques (je pense que c'est l'une des choses qui a changé avec MVC v5. -

Ensuite, appliquez simplement le filtre [ValidateJSONAntiForgeryHeader]à votre action (ou contrôleur) et il devrait être appelé correctement.

Dans ma page de mise en page juste au-dessus, </body>j'ai@AntiForgery.GetHtml();

Enfin, dans ma page Razor, je fais l'appel ajax comme suit:

var formForgeryToken = $('input[name="__RequestVerificationToken"]').val();

$.ajax({
  type: "POST",
  url: serviceURL,
  contentType: "application/json; charset=utf-8",
  dataType: "json",
  data: requestData,
  headers: {
     "__RequestVerificationToken": formForgeryToken
  },
     success: crimeDataSuccessFunc,
     error: crimeDataErrorFunc
});
blubberbo
la source
1
Récupérez-vous toutes les valeurs de votre formulaire manuellement? Pourquoi pas data: $("#the-form").serialize()?
Sinjai
1
@Sinjai Je devrais revoir mon code, mais je crois que je fais aussi un autre traitement là-dedans. ".serialize ()" fonctionnerait également si vous n'avez besoin que des valeurs d'entrée
blubberbo
Pas de soucis, j'étais juste curieux.
Sinjai