# QueryContainer is not populated from json passed in to WebApi via \[FromBody\]

**URL:** <https://discuss.elastic.co/t/querycontainer-is-not-populated-from-json-passed-in-to-webapi-via-frombody/283723>\
**Category:** Elasticsearch\
**Tags:** language-clients\
**Created:** [September 9, 2021, 2:13am UTC](https://discuss.elastic.co/t/querycontainer-is-not-populated-from-json-passed-in-to-webapi-via-frombody/283723 "2021-09-09T02:13:28Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![jthoni](https://avatars.discourse-cdn.com/v4/letter/j/b9e5f3/32.png) [@jthoni](https://discuss.elastic.co/u/jthoni)\
**Post date:** [September 9, 2021, 2:13am UTC](https://discuss.elastic.co/t/querycontainer-is-not-populated-from-json-passed-in-to-webapi-via-frombody/283723/1 "2021-09-09T02:13:28Z")

</div>

We are in the process of upgrading Elasticsearch from v 5.0 to v.6.8. We have a webApi that uses Nest (which we also just upgraded). We have an API that has this:

```auto
        [HttpPost]
        [Route("_cluster/{indices}")]
        public async Task<ClusterResponse> NestQueryCluster([FromBody] ClusterInput clientQuery, [FromUri] string indices, [FromUri] string trendingDays = null)
        {

```

The model for ClusterInput is:

```auto
   /// <summary>
    /// Input model for the cluster
    /// </summary>
    public class ClusterInput
    {
        /// <summary>
        /// Gets or sets the query.
        /// </summary>
        public QueryContainer Query { get; set; }

        /// <summary>
        /// Gets or sets the size of the documents to process
        /// </summary>
        public int? MaxDocumentsToSample { get; set; }

        /// <summary>
        /// Gets or sets beginning time
        /// </summary>
        public DateTimeOffset? From { get; set; }

        /// <summary>
        /// Gets or sets the end time
        /// </summary>
        public DateTimeOffset? To { get; set; }

```

We are sending in payloads like this:

```auto
{
    "query": {
        "bool": {
            "must": [
                {
                    "range": {
                        "creationtimestamp": {
                            "gte": "2021-08-08T00:00:00Z",
                            "lte": "2021-09-07T23:59:59Z"
                        }
                    }
                },
                {
                    "bool": {
                        "should": [
                            {
                                "bool": {
                                    "must": [
                                        {
                                            "bool": {
                                                "should": [
                                                    {
                                                        "terms": {
                                                            "myTerm": [
                                                                "foo",
                                                                "bar"
                                                            ]
                                                        }
                                                  etc...
            ]
        }
    },
    "maxDocumentsToSample": 5000,
    "from": "0001-01-01T00:00:00+00:00",
    "to": "2021-09-08T00:00:00+00:00"
}

```

When it is read, maxDocumentsToSample, from and to all parse to the correct value. "query" is not, however. It is null and we end up with a generic new QueryContainer. In our v5 environment the query parses into a QueryContainer correctly.

I have worked through this, and I think it is related:  
[Custom Serialization | Elasticsearch.Net and NEST: the .NET clients [7.x] | Elastic](https://www.elastic.co/guide/en/elasticsearch/client/net-api/current/custom-serialization.html)

I did do a lot of upgrade work so that our clients read and write data correctly. I am not sure what parsing would be getting used when creating the Nest object from the default FromBody object creation. I am assuming that it is using the incorrect Json library and it does not have the info to create the object from the Json.

I am currently looking into changing my class to create a JOBject instead, and then I will manually convert it using my net client (i.e. RequestResponseSerializer). Is there a better way to do this? Can I override the conversion that is happening when the class is instantiated and have it use Nest.JsonNetSerliazer instead?

Thanks

---

<div class="post-metadata">

**Author:** ![jthoni](https://avatars.discourse-cdn.com/v4/letter/j/b9e5f3/32.png) [@jthoni](https://discuss.elastic.co/u/jthoni)\
**Post date:** [September 17, 2021, 2:16am UTC](https://discuss.elastic.co/t/querycontainer-is-not-populated-from-json-passed-in-to-webapi-via-frombody/283723/2 "2021-09-17T02:16:18Z")

</div>

I am still not sure what is going on, but if anyone else runs into this, this is how I solved it.

I created a custom model binder. This allowed me to get the class, but then create the missing query with custom logic.

This is the model binder (note that it uses System.Web.Http.ModelBinding)

```auto
   public class ClusterInputModelBinder : IModelBinder
    {
        public ClusterInputModelBinder()
        {
        }

        /// <summary>
        /// Bind the ClusterInput class from the body of the request
        /// </summary>
        /// <param name="actionContext">The incoming context</param>
        /// <param name="bindingContext">The outgoing context</param>
        /// <returns>bool as to success</returns>
        public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
        {
            // The success status
            bool success = true;

            // This is what we will set at the model
            ClusterInput clusterInput;

            // Get the model from the body of the request
            using (StreamReader stream = new StreamReader(actionContext.Request.Content.ReadAsStreamAsync().Result))
            {
                string body = stream.ReadToEnd();
                JObject clusterInputJobject = JObject.Parse(body);

                // Deserialize into the ClusterInput. Note that clusterInput.Query will not have the query that came in with the request.
                clusterInput = JsonConvert.DeserializeObject<ClusterInput>(body);

                // Make sure we created the class
                if(clusterInput == null)
                {
                    success = false;
                }

                // Only parse the query if there is one
                if(success && clusterInputJobject.ContainsKey("query"))
                {
                    // Get the query as a stream
                    byte[] byteArray = Encoding.ASCII.GetBytes(JsonConvert.SerializeObject(clusterInputJobject["query"]));
                    MemoryStream ms = new MemoryStream(byteArray);

                    // Use a fake client to get access to the Deserializer and create the QueryContainer
                    ElasticClient client = getFakeClient();
                    QueryContainer queryContainer = (QueryContainer)client.RequestResponseSerializer.Deserialize(typeof(QueryContainer), ms);

                    // Set it on our return object
                    clusterInput.Query = queryContainer;

                    if(clusterInput?.Query == null)
                    {
                        success = false;
                    }
                }
            }

            if(success)
            {
                bindingContext.Model = clusterInput;
            }            

            return success;
        }

        private ElasticClient getFakeClient()
        {
            // build a uri from the url
            var node = new Uri("http://fake.com");

            // create a pool with the Uri
            var pool = new SingleNodeConnectionPool(node);

            ConnectionSettings settings = new ConnectionSettings(pool, sourceSerializer: JsonNetSerializer.Default);

            return new ElasticClient(settings);
        }
    }
}

```

I then updated my api to use it as such:

```auto
        public async Task<ClusterResponse> NestQueryCluster([ModelBinder(BinderType = typeof(ClusterInputModelBinder))] ClusterInput clientQuery, [FromUri] string indices, [FromUri] string trendingDays = null)
        {

```

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/elastic/original/3X/1/a/1ac57faf039f6b580b3f104ef42a2a89e41014de.png) [@system](https://discuss.elastic.co/u/system)\
**Post date:** [October 15, 2021, 2:16am UTC](https://discuss.elastic.co/t/querycontainer-is-not-populated-from-json-passed-in-to-webapi-via-frombody/283723/3 "2021-10-15T02:16:26Z")

</div>

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.
