Deserialization of the form does not work

advertisements

I have an asynchonous httpPost that serializes my form data and commits it to my controller. There I try to get my form data serialized into my view model class but all the values are null or have the default value assigned.

public ActionResult GetSalesData(string vmString)
{
    -serialization...
    -use the data to select some other data
    return new JsonResult { Data = d, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
}

For the serialization I tried so far these two ways:

1.)

    { vmString: $('form').serialize() }

result:

Dataset.Ids=3,7,12&Type=Sales&DataSources=BeverageType&DisplayModes=Volume&SeriesTypes=Lines&SalesVm.DisplayOptions.ShowAverage=false&SalesVm.DisplayOptions.ShowTargetLine=false&ActionName=Sales_SelectBeverageTypes&Mode=LightboxInWizard&SelectedDatasetIdsWorkingCopy=3&SearchTerm=

2.)

    { vmString: JSON.stringify($('form')) }

result:

{"length":2,"prevObject":{"0":{"jQuery1710039964356962994385":1,"location":{}},"context":{"jQuery1710039964356962994385":1,"location":{}},"length":1},"context":{"jQuery1710039964356962994385":1,"location":{}},"selector":"form","0":{"Dataset.Ids":{},"Type":{},"DataSources":{"jQuery1710039964356962994385":15},"3":{"jQuery1710039964356962994385":16},"DisplayModes":{"0":{"jQuery1710039964356962994385":42},"1":{"jQuery1710039964356962994385":43},"2":{"jQuery1710039964356962994385":44},"3":{"jQuery1710039964356962994385":45}},"SeriesTypes":{"0":{"jQuery1710039964356962994385":46},"1":{"jQuery1710039964356962994385":47}},"SalesVm.DisplayOptions.ShowAverage":{"0":{"jQuery1710039964356962994385":48},"1":{"jQuery1710039964356962994385":49}},"SalesVm.DisplayOptions.ShowTargetLine":{"0":{"jQuery1710039964356962994385":50},"1":{"jQuery1710039964356962994385":51}}},"1":{"ActionName":{},"Mode":{},"SelectedDatasetIdsWorkingCopy":{},"SearchTerm":{"jQuery1710039964356962994385":35}}}

To deserialize, I tried:

m = (StatisticsViewerViewModel)new JsonSerializer().Deserialize(new System.IO.StringReader(vmString), typeof(StatisticsViewerViewModel));
m = (StatisticsViewerViewModel)new JsonSerializer().Deserialize(new System.IO.StringReader(vmString), vmString.GetType());
m = JsonConvert.DeserializeObject<StatisticsViewerViewModel>(vmString);

DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(StatisticsViewerViewModel));
m = (StatisticsViewerViewModel) ser.ReadObject(stream);

I checked that all my fields are inside the form:

 @using (Html.BeginForm())
{
   some partial views containing some fields, all using the same model..
}

I also checked that the used View Model as well as all nested models do have an empty constructor.

Are there different ways to de-/serialize the form data? And what else could I check to make sure everything is as it should be?

  • EDIT -

ViewModel-Root:

public class StatisticsViewerViewModel
{
    public String BreadcrumbName { get; set; }
    public String ActionName { get; set; }
    public StatisticsType Type { get; set; }
    public DropDownListModel DataSourceList { get; set; }
    public MultiSelectionModel Dataset { get; set; }
    public SalesViewModel SalesVm { get; set; }
    //public EventsViewModel EventsVm { get; set; }
    public ChartExportOptions ExportOptions { get; set; }

    public StatisticsViewerViewModel()
    {
        DataSourceList = new DropDownListModel();
        Dataset = new MultiSelectionModel();
        SalesVm = new SalesViewModel();
        ExportOptions = new ChartExportOptions();
    }

    public enum StatisticsType
    {
        Sales,
        Events
    }
}

Nested ViewModels

public class SalesViewModel
{
    public SalesDisplayOptions DisplayOptions { get; set; }
    public RadioButtonModel DisplayModes { get; set; }      // Volume, Value, ..
    public RadioButtonModel SeriesTypes { get; set; }       // Line, Bar, ..

    public SalesViewModel(bool initialize = false)
    {
        if (initialize) { Initialize(); }
    }
}

public class SalesDisplayOptions
{
    public DisplayMode Mode { get; set; }
    public SeriesType Type { get; set; }
    public bool ShowAverage { get; set; }
    public bool ShowTargetLine { get; set; }

    public enum SeriesType
    {
        Lines, ...
    }

    public enum DisplayMode
    {
        Value, ...
    }

}

A relevant point might be that the post is fired by kendoChart. Here the interesting block inside the view:

....
<div id="chart"></div>
....
@this.ScriptBlock(
@<script type="text/javascript">
$("#chart").kendoChart({
             dataSource: new kendo.data.DataSource({
                 transport: {
                     read: {
                         url: actionUrl,
                         data: { vmString: $('form').serialize() },
                         dataType: "json",
                         contentType: "application/json; charset=utf-8"
                     }
                 },
                 sort: ...
 ....

To check whether the problems are related to the kendoChart-Object, I testwisely implemented a manual POST:

....
<div class="round-corner-bottom-right">
        <button id="send-form" type="button">
            <span class="button-label">Send Form Data</span>
        </button>
</div>
....

@this.ScriptBlock(
@<script type="text/javascript">

     $('document').ready(function () {

        $('#send-form').on('click', function () {

             var data = $('form').serialize();

             $.ajax({
                 type: "POST",
                 url: actionUrl,
                 data: data,
                 cache: false,
                 success: function (returnData) {
                 }
             });

     }); // document ready

The problem does not persist in this scenario, all values are set as expected. So there seems to be a problem with the kendoChart-methode.


Have you tired using allowing default model binder to handle it rather than trying to deserialize and managing it yourself?

So

public ActionResult GetSalesData(string vmString)

becomes this

public ActionResult GetSalesData(MyModel vmString)