Come passare il tipo complesso utilizzando json nel controller MVC di ASP.NET

Ho una vista che consente a un utente di inserire / modificare i dati per un nuovo widget. Mi piacerebbe creare questi dati in un object json e inviarlo al mio controller tramite AJAX in modo da poter eseguire la convalida sul server senza un postback.

Ho funzionato tutto, tranne che non riesco a capire come passare i dati in modo che il mio metodo controller possa accettare un tipo di widget complesso invece di singoli parametri per ogni proprietà.

Quindi, se questo è il mio object:

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

Mi piacerebbe che il mio metodo controller assomigliasse a qualcosa del genere:

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

Attualmente, il mio jQuery si presenta così:

 var formData = $("#Form1").serializeArray(); $.post("/Widget/Save", formData, function(result){}, "json"); 

Il mio modulo (Form1) ha un campo di input per ogni proprietà sul Widget (Id, Nome, Prezzo). Funziona alla grande, ma alla fine passa ogni proprietà del Widget come parametro separato al mio metodo di controllo.

C’è un modo per “intercettare” i dati, magari usando un ActionFilterAttribute e deserializzarlo su un object Widget prima che venga chiamato il metodo del mio controller?

Grazie Jeff, questo mi ha fatto sulla strada giusta. DefaultModelBinder è abbastanza intelligente da fare tutta la magia per me … il mio problema era nel mio tipo di widget. Nella mia fretta, il mio tipo è stato definito come:

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

Si noti che il tipo ha campi pubblici anziché proprietà pubbliche. Una volta modificati quelli in proprietà, ha funzionato. Ecco il codice sorgente finale che funziona correttamente:

Widget.aspx:

 <%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" AutoEventWireup="true" CodeBehind="Widget.aspx.cs" Inherits="MvcAjaxApp2.Views.Home.Widget" %>    

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

Si noti che (nella soluzione di MrDustpan ) il widget del nome parametro nel metodo MVC Action deve corrispondere al prefisso utilizzato nell’attributo name nel file ASPX.

Se questo non è il caso, il metodo Action riceverà sempre un object nullo .

  - OK  - FAILS 

Phil Haack ha un buon post sul bind modello che potrebbe essere utile. Non al 100% di cosa stai parlando qui, ma penso che potrebbe darti una migliore comprensione generale di DefaultModelBinder.

Quello che vuoi fare è strutturare il tuo object modulo javascript nello stesso modo in cui è strutturato il tuo object backend:

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

Quindi usa il plugin toJSON per convertirlo nella stringa sopra. Invia questa stringa al tuo back-end e usa qualcosa come le librerie JayRock per convertirlo in un nuovo object Widget.