How to pass complex type using json to ASP.NET MVC controller

I have a View that allows a user to enter/edit data for a new Widget. I’d like to form up that data into a json object and send it to my controller via AJAX so I can do the validation on the server without a postback.

I’ve got it all working, except I can’t figure out how to pass the data so my controller method can accept a complex Widget type instead of individual parameters for each property.

So, if this is my object:

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

I’d like my controller method to look something like this:
public JsonResult Save(Widget widget)
{
   ...
}

Currently, my jQuery looks like this:
var formData = $("#Form1").serializeArray();

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

My form (Form1) has an input field for each property on the Widget (Id, Name, Price). This works great, but it ultimately passes each property of the Widget as a separate parameter to my controller method.

Is there a way I could “intercept” the data, maybe using an ActionFilterAttribute, and deserialize it to a Widget object before my controller method gets called?

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

Thanks Jeff, that got me on the right path. The DefaultModelBinder is smart enough to do all the magic for me…my problem was in my Widget type. In my haste, my type was defined as:

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

Notice that the type has public fields instead of public properties. Once I changed those to properties, it worked. Here’s the final source code that works correctly:

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

Method 2

Note that (in MrDustpan’s solution) the parameter name widget in the MVC Action method must match with the prefix used in the name attribute in the ASPX file.

If this is not the case then the Action method will always receive a null object.

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

Method 3

Phil Haack has a good blog post about model binding that might be helpful. Not 100% what you’re talking about here, but I think it might give you a better overall understand about the DefaultModelBinder.

Method 4

What you want to do is structure your javascript form object in the same way your backend object is structured:

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

Then use the toJSON plugin to convert it into the above string. You send this string to your backend and use something like the JayRock libraries to convert it to a new Widget object.


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x