2008-11-06 15 views
32

Tengo una vista que permite a un usuario ingresar/editar datos para un nuevo widget. Me gustaría formar esos datos en un objeto JSON y enviarlos a mi controlador a través de AJAX para que pueda hacer la validación en el servidor sin una devolución de datos.Cómo pasar el tipo complejo usando json al controlador ASP.NET MVC

Lo tengo todo funcionando, excepto que no puedo descifrar cómo pasar los datos para que mi método de controlador pueda aceptar un tipo de widget complejo en lugar de parámetros individuales para cada propiedad.

lo tanto, si este es mi objeto:

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

Me gustaría que mi método de controlador para ser algo como esto:

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

Actualmente, mi jQuery se ve así:

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

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

Mi formulario (Form1) tiene un campo de entrada para cada propiedad en el Widget (Id, Nombre, Precio). Esto funciona muy bien, pero finalmente pasa cada propiedad del Widget como un parámetro separado a mi método de controlador.

¿Hay alguna manera de poder "interceptar" los datos, tal vez usando un ActionFilterAttribute, y deserializarlos en un objeto Widget antes de que se llame a mi método de controlador?

Respuesta

24

Gracias Jeff, eso me puso en el camino correcto. El DefaultModelBinder es lo suficientemente inteligente como para hacer toda la magia para mí ... mi problema estaba en mi tipo de widget. En mi prisa, mi tipo se definió como:

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

Tenga en cuenta que el tipo tiene campos públicos en lugar de propiedades públicas. Una vez que los cambié a propiedades, funcionó. Aquí está el código fuente final que funciona correctamente:

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

Impresionante, me alegro de que lo hayas reparado. ¡Y gracias por publicar cómo lo arregló, eso ayudará mucho a otros en el futuro! –

+1

Los campos públicos son el engendro del demonio en .NET. Rompen todo. ¡TODO LO QUE LE DIGO! – Will

+0

Gracias. Esto me ayudó. –

2

Lo que se quiere hacer es la estructura de su formulario objeto de javascript de la misma manera que el objeto está estructurado back-end:

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

A continuación, utilice el plugin toJSON para convertirlo en la cadena anterior. Usted envía esta cadena a su servidor y utiliza algo como las bibliotecas JayRock para convertirlo en un nuevo objeto Widget.

4

Phil Haack tiene a good blog post sobre el modelo de encuadernación que pueda ser útil. No es el 100% de lo que estás hablando aquí, pero creo que podría darte una mejor comprensión general sobre DefaultModelBinder.

6

Tenga en cuenta que (en de MrDustpan solución) el parámetro de nombre de El widget en el método MVC Action debe coincidir con el prefijo utilizado en el nombre attri bute en el archivo ASPX.

Si este no es el caso, el método de acción siempre recibirá un objeto nulo .

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

Excelente punto y fácilmente pasado por alto. Parece ser sensible a mayúsculas y minúsculas también. –

Cuestiones relacionadas