ASP.NET MVC: GET parameters are not deserialized properly

I need to pass a complex object representing a data filter to an action using a GET that returns the filtered dataset in a csv file.

The filter object on the client looks like this (much more complicated in practice, simplified for brevity):

var filter = {
  Folders = [
    { Positive: true, Reference: { Id: 19, Name: "Container" } },
    { Positive: true, Reference: { Id: 37, Name: "Bullseye" } },
  ]
}

      

The corresponding server-side classes look something like this:

public class MyFilter
{
    public List<MyComparison> Folders { get; set; }
}
public class MyComparison
{
    public bool Positive { get; set; }
    public MyReference Reference { get; set; }
}
public class MyReference
{
    public int Id { get; set; }
    public string Name {get; set; }
}

      

My actions look like this:

[HttpGet]
public FileContentResult Export(MyFilter filter, string sort, bool sortAscending)
{
    string data = GetCsvData(filter, sort, sortAscending);
    return this.File(StrToByteArray(data), "text/csv", "Data.csv");
}

      

I tried to call this action from javascript like this:

function exportFilter(aFilter) {
    var params = { filter: aFilter, sort: "Name", sortAscending: true };
    var destination = "MyController/Export?" + decodeURIComponent($.param(params));
    document.location = destination;
}

      

As part of the activity, the sort and sortAscending parameters are correctly filled. The filter is an object of type MyFilter, but its Folders property is null.

Is ASP.NET MVC failing to properly deserialize complex parameters (i.e. in a GET context)? What is the correct way to solve this problem?

+3


source to share


2 answers


It can bind complex objects / parameters, the problem is how the parameters are sent. For example, you send:

http://localhost/Home/Export?filter[Folders][0][Positive]=true&filter[Folders][0][Reference][Id]=19&filter[Folders][0][Reference][Name]=Container&filter[Folders][1][Positive]=true&filter[Folders][1][Reference][Id]=37&filter[Folders][1][Reference][Name]=Bullseye&sort=Name&sortAscending=true

      

But the MVC binder expects a format like this:



http://localhost/Home/Export?filter.Folders[0].Positive=true&filter.Folders[0].Reference.Id=19&filter.Folders[0].Reference.Name=Container&filter.Folders[1].Positive=true&filter.Folders[1].Reference.Id=37&filter.Folders[1].Reference.Name=Bullseye&sort=Name&sortAscending=true 

      

I'm not sure if the easiest way to construct a string matching this pattern is from a javascript object.

+2


source


The data binding algorithm in Asp.net MVC is not very good at deserializing complex inputs in .NET types. At best, you will get some strange results and / or slow performance when compared to other specialized solutions. In this case, Json.NET provides much better results when deserializing json data into .NET types and is very fast.

You should pass these filters as a regular string parameter and deserialize it inside the action using Json.NET. Something like that:



using Newtonsoft.Json;

public ActionResult MyAction(string myFilters)
{
    var deserializedObject = JsonConvert.DeserializeObject(myFilters);
}

      

+3


source







All Articles