How to receive dynamic data in Web API controller Post method

Andrus picture Andrus · Nov 25, 2015 · Viewed 14.3k times · Source

jqgrid posts json data in POST request buffer as

{"headerData": {
    "Tasudok": "134",
    "Kuupaev": "2015-11-23",
    "Dokumnr": "135319"
   },


"rowData": {
  "Toode":"",
  "Kogus":"0.0000",
  "Nimetus":"öäölä<a",
  "_rowsum":"0.00",
  "Id":"1639",
  "Dokumnr":"135319",
  "_oper":"edit",
  "_rowid":"1639"
  }
}

Data is posted to ASP.NET MVC4 Web API using URL like API/Entity/someid?culture=en&layout=1 with default routing.

headerData and rowData value properties are defined in runtime and can vary.

For example in some call rowData may contain additional properties and some rowData properties may be missing.

culture and layout query string paramaters are optional.

How to receive parameters in WebAPI controller ?

I tried

public class EntityController : APIController
{

public class PostParams {
    public string culture { get; set; }
    public int? layout { get; set; }
    }

    public HttpResponseMessage Post(string id, 
      [FromUri]PostParams optionalParams,
      [FromBody]IList<NameValue> headerData,
      [FromBody]IList<NameValue> rowData )
    { ... }


public class NameValue
{
    public string name, value;
}
}

But headerData and rowData are empty. How to get all parameters?

Answer

plog17 picture plog17 · Nov 26, 2015

If the structure of the JSON does not change

Having this will permit you to send the body like the one you provided at a url like API/Entity/someid?culture=en&layout=1.

To specify optional query parameter in your controller route, give them a default value like:

public class EntityController : APIController
{
    public HttpResponseMessage Post([FromUri]string culture="EN", [FromUri]int layout=1, YourBody body )
    { ... }
}

If YourBody is always like the one you mentionned, something like this should be deserialized automatically:

public class YourBody
{
    public Dictionary<string, string> HeaderData {get; set;}
    public Dictionary<string, string> RowData{get; set;}
}

and would give you full access to any element of the body.

If the structure of the JSON can change

Something like this would permit the receive any kind of json:

public HttpResponseMessage  Post([FromBody]JToken body)
{
    // Process the body
    return ...
}

You will need some extra validation since no object deserialization will be made. The only think you'll know is that your body is a JSON.

You therefore may want to parse it to see if it looks like what you are expecting. See that post about how to access element of a JSON with JToken.

For instance, you could do something like the following to handle a changing body content and still handle optional query parameters of your route :

public HttpResponseMessagePost([FromBody]JToken body, [FromUri]string culture="EN", [FromUri]int layout=1)
{
    JObject headerData= body["headerData"].Value<JObject>();
    JObject headerData= body["rowData"].Value<JObject>();
    return ...;
}

You may also read this about other alternatives for posting raw data to a webapi controller.