32 votes

Comment passer un type complexe en utilisant json à un contrôleur ASP.NET MVC ?

J'ai une vue qui permet à un utilisateur d'entrer/modifier des données pour un nouveau Widget. J'aimerais formuler ces données dans un objet json et les envoyer à mon contrôleur via AJAX afin de pouvoir effectuer la validation sur le serveur sans postback.

Tout fonctionne, sauf que je n'arrive pas à trouver comment transmettre les données pour que la méthode de mon contrôleur puisse accepter un type de widget complexe au lieu de paramètres individuels pour chaque propriété.

Donc, si c'est mon objet :

public class Widget
{
   public int Id { get; set; }
   public string Name { get; set; }
   public decimal Price { get; set; }
}

J'aimerais que la méthode de mon contrôleur ressemble à quelque chose comme ceci :

public JsonResult Save(Widget widget)
{
   ...
}

Actuellement, mon jQuery ressemble à ceci :

var formData = $("#Form1").serializeArray();

$.post("/Widget/Save",
   formData,
   function(result){}, "json");

Mon formulaire (Form1) comporte un champ de saisie pour chaque propriété du widget (Id, Nom, Prix). Cela fonctionne très bien, mais au final, chaque propriété du widget est transmise comme un paramètre distinct à la méthode de mon contrôleur.

Existe-t-il un moyen d'"intercepter" les données, peut-être en utilisant un attribut ActionFilterAttribute, et de les désérialiser en un objet Widget avant que la méthode de mon contrôleur ne soit appelée ?

25voto

MrDustpan Points 2900

Merci Jeff, cela m'a mis sur la bonne voie. Le DefaultModelBinder est assez intelligent pour faire toute la magie pour moi... mon problème était dans mon type de Widget. Dans ma hâte, mon type a été défini comme :

public class Widget
{
   public int Id;
   public string Name;
   public decimal Price;
}

Remarquez que le type a des champs publics au lieu de propriétés publiques. Une fois que je les ai changés en propriétés, cela a fonctionné. Voici le code source final qui fonctionne correctement :

Widget.aspx :

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" AutoEventWireup="true" CodeBehind="Widget.aspx.cs" Inherits="MvcAjaxApp2.Views.Home.Widget" %>
<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
    <script src="../../Scripts/jquery-1.2.6.js" type="text/javascript"></script>   
    <script type="text/javascript"> 
    function SaveWidget()
    {
        var formData = $("#Form1").serializeArray();

        $.post("/Home/SaveWidget",
        formData,
        function(data){
            alert(data.Result);
        }, "json");
    }
    </script>
    <form id="Form1">
        <input type="hidden" name="widget.Id" value="1" />
        <input type="text" name="widget.Name" value="my widget" />
        <input type="text" name="widget.Price" value="5.43" />
        <input type="button" value="Save" onclick="SaveWidget()" />
    </form>
</asp:Content>

HomeController.cs :

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

namespace MvcAjaxApp2.Controllers
{
    [HandleError]
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            ViewData["Title"] = "Home Page";
            ViewData["Message"] = "Welcome to ASP.NET MVC!";
            return View();
        }

        public ActionResult About()
        {
            ViewData["Title"] = "About Page";
            return View();
        }

        public ActionResult Widget()
        {
            ViewData["Title"] = "Widget";
            return View();
        }

        public JsonResult SaveWidget(Widget widget)
        {
            // Save the Widget
            return Json(new { Result = String.Format("Saved widget: '{0}' for ${1}", widget.Name, widget.Price) });
        }
    }
    public class Widget
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public decimal Price { get; set; }
    }
}

6voto

Simon Sanderson Points 486

Notez que (dans MrDustpan's solution) le paramètre nom widget dans la méthode d'action MVC doit correspondre au préfixe utilisé dans le fichier nom dans le fichier ASPX.

Si ce n'est pas le cas, la méthode Action recevra toujours un message null objet.

<input type="text" name="widget.Text" value="Hello" /> - OK
<input type="text" name="mywidget.Text" value="Hello" /> - FAILS

4voto

Jeff Sheldon Points 1509

Phil Haack a un bon article de blog sur la liaison des modèles qui pourrait être utile. Ce n'est pas à 100% ce dont vous parlez ici, mais je pense que cela pourrait vous donner une meilleure compréhension globale de DefaultModelBinder.

2voto

Sugendran Points 1434

Ce que vous voulez faire, c'est structurer votre objet formulaire javascript de la même manière que votre objet backend est structuré :

{ Id : "id", Name : "name", Price : 1.0 }

Utilisez ensuite le plugin toJSON pour le convertir en la chaîne ci-dessus. Vous envoyez cette chaîne à votre backend et utilisez quelque chose comme les bibliothèques JayRock pour la convertir en un nouvel objet Widget.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X