Question

I have a request like this:

filter[logic]:and
filter[filters][0][value]:a
filter[filters][0][operator]:startswith
filter[filters][0][field]:result
filter[filters][0][ignoreCase]:true

I need to receive it on the Controller but I don't know exactly how. I have tried this view model:

{
    public class SearchFilterViewModel
    {
        public string logic { get; set; }
        public List<SearchFilterFiltersViewModel> filters { get; set; }
    }

    public class SearchFilterFiltersViewModel
    {
        public string value { get; set; }
        //public string operator { get; set; }
        public string field { get; set; }
        public bool ignoreCase { get; set; }
    }
}

But the Controller receives it all null. operator property is commented because operator is a reserved keyword, I don't know how to make Asp.Net to use it. And I don't know if this is the cause of the problem.

Note that I can't change the request body pattern because it comes from this Kendo Widget.

This is my Controller(test version):

public ActionResult Text(SearchFilterViewModel filter)
{
    return Json("", JsonRequestBehavior.AllowGet);
}
Was it helpful?

Solution

Here is working solution

Model:

public class SearchFilterViewModel
{
    public string logic { get; set; }
    public List<SearchFilterFiltersViewModel> filter { get; set; }
}

public class SearchFilterFiltersViewModel
{
    public string value { get; set; }
    public string oper { get; set; }
    public string field { get; set; }
    public bool ignoreCase { get; set; }
}

Then you can write custom IValueProvider where you can override usual parsing mechanism like this:

public class KendoValueProvider : NameValueCollectionValueProvider
{
    public KendoValueProvider(NameValueCollection originalCollection)
        : base(UpdateCollection(originalCollection), CultureInfo.InvariantCulture)
    {
    }

    private static NameValueCollection UpdateCollection(NameValueCollection collection)
    {
        NameValueCollection result = new NameValueCollection();

        foreach (string key in collection.Keys)
        {
            // ignore all other request
            if (!key.StartsWith("filter"))
                return null;

            var newKey = key
                .Replace("[filters]", string.Empty)
                .Replace("filter[logic]", "logic")
                .Replace("[value]", ".value")
                .Replace("[operator]", ".oper")
                .Replace("[field]", ".field")
                .Replace("[ignoreCase]", ".ignoreCase");

            var value = collection[key];

            result.Add(newKey, value);
        }
        return result;
    }
}

Then you need to write ValueProviderFactory that will register this ValueProvider like this:

public class KendoValueProviderFactory : ValueProviderFactory
{
    public override IValueProvider GetValueProvider(ControllerContext controllerContext)
    {
        return new KendoValueProvider(controllerContext.HttpContext.Request.QueryString);
    }
}

And the last step is just register it in Global.asax file

ValueProviderFactories.Factories.Add(new KendoValueProviderFactory());

And sample Action

[HttpGet]
public ActionResult Index(SearchFilterViewModel model)
{
      return Json(model, JsonRequestBehavior.AllowGet);
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top