Search code examples
jqueryasp.netajaxasp.net-web-api

How to post complex object including lists to ASP Web API 2


I am trying to post an complex object which include several list/arrays of strings, via an jQuery ajax call. Only the scalar properties of the object seems to get mapped, not the arrays.

I've done some searching around, but cannot find any examples or solutions to this exact scenario.

web API method:

[HttpPost]
public IHttpActionResult Save(MenuSearchGuideEntry model)
{
    //Do stuff
    return Ok("");
}

MenuSearchGuideEntry object:

[Table("MENUSOEGNING_GUIDE")]
public class MenuSearchGuideEntry
{
    [Key]
    [Column("RAEKKEID")]
    [Display(Name="Række id")]
    public Decimal RowId { get; set; }

    [Display(Name = "Label id")]
    [Column("LABELID")]
    public int? LabelId { get; set; }

    [Column("ACTION")]
    [Display(Name = "Action")]
    public string JsonAction { get; set; }

    [Column("FORCESEARCH")]
    [Display(Name = "Tving søgning")]
    public bool ForceSearch { get; set; }

    [Column("ORD")]
    [Display(Name = "Søgeord")]
    public string SearchKeysString { get; protected set; }        
    public List<string> SearchKeys
    {
        get
        {
            return ToStringList(SearchKeysString, ' ');
        }
        set
        {
            SearchKeysString = value.Aggregate<string>((a, b) => a + " " + b);
        }
    }


    [Column("SKJULTEFIRMAER")]
    [Display(Name = "Skjulte firmaer")]
    public string HiddenCompaniesString { get; protected set; }
    public List<string> HiddenCompanies
    {
        get
        {
            return ToStringList(HiddenCompaniesString, ' ');
        }
        set
        {
            HiddenCompaniesString = value.Aggregate<string>((a, b) => a + " " + b);
        }
    }
    [Column("SKJULTEDOMAENER")]
    [Display(Name = "Skjulte domæner")]
    public string HiddenDomainsString { get; protected set; }
    public List<string> HiddenDomains
    {
        get
        {
            return ToStringList(HiddenDomainsString, ' ');
        }
        set
        {
            HiddenDomainsString = value.Aggregate<string>((a, b) => a + " " + b);
        }
    }
    [Column("PRIORITET")]
    [Display(Name = "Prioritet")]
    public int? Priority { get; set; }


    private List<string> ToStringList(string separatedString, char separator)
    {
        return string.IsNullOrEmpty(separatedString) 
            ? new List<string>() 
            : eparatedString.Split(separator).ToList();
    }
}

jQuery Ajax call:

function ajaxPost(data, url, redierctUrl) {
    $.ajax({
        url: url,
        data: JSON.stringify(data),
        type: 'POST',        
        contentType: 'application/json',
        success: function () {
            window.location.href = redierctUrl;
        },
        error: function (msg) {
       
        }
    });
}

object posted via Ajax:

{
    "RowId":"1920",
    "priority":"",
    "labelId":"9999",
    "forcesSearch":"False",
    "jsonAction":"KBA TEST",
    "SearchKeys":["ZZZ","YYY","XXX"],
    "HiddenDomains":["VAU","THG","MEK",""],
    "HiddenCompanies":["MGM"]
}

Solution

  • I've played around with this a bit. I believe what is happening is that Wep Api uses the getter of the List<string> properties (getting a new empty list) and then adding strings to the list. Once Web Api is done adding the strings to the list, the list is just left without references and gets garbage collected. The setter does not seem to get called.

    If you don't want to change you model to actually have real List<string> members, then you can get around this by returning null instead of new List<string> from the ToStringList method. Then, when Web API uses the getter and gets null, it will call the setter later on.

    Still, I think you'd be well advised to store the SearchKeys etc in real List<string> members in the class, and then instead have a property that returns the contents of the list as space separated words:

    [Column("ORD")]
    [Display(Name = "Søgeord")]
    public string SearchKeysString { get { return SearchKeys.Aggregate<string>((a, b) => a + " " + b); } }
    public List<string> SearchKeys { get; set; }