views:

216

answers:

4

I've been looking on forums for 2 days now and can't find a good answer so I'll just post it.

I appear to be having a problem posting JSON back to the controller to save. The JSON should map to model view but it keeps getting default(constructor)values rather then the values from the POST.

We have a series of JS widgets that contain a data field with json in them. We do all our data manipulation in these widget objects on the client side. When a user wants to save we grab the data we need from the widgets involved and we put it into another JSON object that matches a ViewModel and POST that back to the server.

For example:

 $("#Save").click(function () {
        if (itemDetails.preparedForSubmit() && itemConnections.preparedForSubmit()) {
            itemComposite.data.Details = itemDetails.data;
            itemComposite.data.Connections= itemConnections.data;
            $.post(MYURL, itemComposite.data);
        } else {
            alert("failed to save");
        }
    });

The preparedForSubmit() method simple does stuff like any validation checks or last minute formatting you might need to do client side.

The itemDetails widgets data matches a ViewModel.

The itemConnections widgets data matches a collection of ViewModels.

The Controller looks like this:

    [HttpPost]
    virtual public JsonResult SaveItemDetailsComposite(ItemComposite inItemData)
    {
        if (ModelState.IsValid)
        {
            try
            {
               _Mapper.Save(itemComposite.Details , itemComposite.Connections);
               return Json(true);                   
            }
            catch (Exception ex)
            {
                _log.Error("Exception " + ex.InnerException.Message);
                throw;
            }
        }

        return Json(SiteMasterUtilities.CreateValidationErrorResponse(ModelState));
    }

The ItemComposite Class is a simple View Model that contains a single itemDetails object and a collection of itemConnections. When it returns data to here it is just getting the default data as if it got a new ItemComposite rather than converting the POST data.

in Firebug I see the data is posted. Although it looks weird not automatically formatted in firebug.

A: 

You may want to look into a framework like JSON.NET to ensure that your data is being serialized properly when it gets supplied to your Action.

JSON.NET seems like it's one of the main stream frameworks: http://json.codeplex.com/releases/view/43775

Hope this helps.

Cory

SyntaxC4
Thanks I'm a .Net noob came from GWT env, I'll read up on this see how it works.
Chris
+1  A: 

Are you saying that itemComposite.data is formatted as a JSON object? If so, I'm pretty sure you're going to have to de-serialize it before you can cast it to your object. Something like:

ItemComposite ic = jsSerializer.Deserialize<ItemComposite>(this.HttpContext.Request.Params[0]);
ThatSteveGuy
I just tried this. it seems to give me the same result as inItemData. Params[0] looks like what my firebug shows me and ic looks the same as inItemData. I'm sure this has something to do with either the way I make my request or the way data binding works.Params[0] looks like {%7b%22TaskDetails%22%3a%7b%7d%2c%22LaborTypes%22%3a%5b%7b%22LaborTypeID%22%3a93%2c%22LaborTypeID%22%3a1...
Chris
You're seeing that in the net-->response part of firebug? If so, it's encoded wrong. It should look like json object, not a bunch of url encoding. Since you want to send directly to an Action Method argument, take a look at this post by Haack and see if it helps: http://haacked.com/archive/2010/04/15/sending-json-to-an-asp-net-mvc-action-method-argument.aspx
ThatSteveGuy
A: 

You could also use the JSON Serializer in WCF: http://msdn.microsoft.com/en-us/library/system.runtime.serialization.json.datacontractjsonserializer.aspx

SO wouldn't let me put both links in one answer, sorry for the split answer.

SyntaxC4
A: 

Thanks everyone. I think I have solved my problem and I'm pretty sure that I had four issues. For the most part I followed thatSteveguys's suggestion and read more on this article: http://haacked.com/archive/2010/04/15/sending-json-to-an-asp-net-mvc-action-method-argument.aspx

Using jQuery's post() method and specifying json as the type didn't seem to actually send it as json. By using the ajax() method and specifying json it sent it as json.

The JSON.serialize() method was also need to cleanly send over the json.

Also my ViewModel design was a big problem. We are using the MS code analytic build junk and it didn't want me having a setter for my collections in the ViewModel. So me being from a java/hibernate world, thought it didn't need them to bind and it would just come in as a serialized object magically. Once I just suppressed the error and reset up my setters. I am getting the collections now in my controller.

I believe using the MVC2 Future's Value Providers are doing something but it still doesn't convert json dates robustly, So I am still investigating the best way to do that.

I hope my issues help out others.

UPDATE: using this method to update collections of data appears to be super slow. A collection with 200 entries in it and 8 fields per entry takes 3 minutes to get to the controller. Just 1 or 2 entries take very little time. The only thing I know of that is happening between here is data binding to the model view. I don't know if MVC2 provides a easy way to send this much data and bind it.

Chris