Hi,
As per this forum thread:
http://forums.asp.net/t/1795976.aspx/1?How+to+bind+this+querystring+to+parameters+on+an+API+Controller+Action+GET+
There seems to be a difference in behavior when binding complex models between GET and POST.
In a POST where the query is passed in the body of the message, the DefaultModelBinder will work fine when binding the following data:
filter[logic]=and&filter[filters][0][field]=FolderID&filter[filters][0][operator]=eq&filter[filters][0][value]=2
Which gets bound to this server side model:
public class GridFilter
{
public string Operator { get; set; }
public string Field { get; set; }
public string Value { get; set; }
}
public class GridFilters
{
public List<GridFilter> Filters { get; set; }
public string Logic { get; set; }
}
//Action signature:
[System.Web.Mvc.HttpPost]
public IQueryable<Building> Get(WebApi1.Models.GridFilters filter = null)
{...}
On the other hand, when changing the ApiController to handle a GET where the query is passed in the querystring, then the DefaultModelBinder will pass null into the controller action (of course I did change my client code to do a GET as well).
I tried to nail down the problem by implementing a Custom Model Binder, and within the Bind method, I can see that when using POST, the data is passed in the NameValueCollectionValueProvider of the CompositeValueProvider, but when using a GET, the data is in the QueryStringValueProvider.
What I also noted is that if I call GetKeysFromPrefix("") on the CompositeValueProvider while doing GET, since there is already an empty key in the NameValueCollectionValueProvider, I get returned that one instead of the one in QueryStringValueProvider. This seems to be related to this code in CompositeValueProvider:
public virtual ValueProviderResult GetValue(string key)
{
return (from provider in this
let result = provider.GetValue(key)
where result != null
select result).FirstOrDefault();
}
public virtual IDictionary<string, string> GetKeysFromPrefix(string prefix)
{
return (from provider in this
let result = GetKeysFromPrefixFromProvider(provider, prefix)
where result != null && result.Any()
select result).FirstOrDefault() ?? new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
}
Since the NameValueCollectionValueProvider is at index 1 and QueryStringValueProvider is at index 2, using FirstOrDefault() will pick the one in NameValueCollectionValueProvider everytime.
I hope I'm not too way off track though :-)
Somehow, it seems that between the two use case there is something that doesn't work as expected, but I can't pinpoint further. I hope this will help you identify the source of the observed behavior.
Thank you.