shlatchz
shlatchz

Reputation: 1652

passing base object with inherited object value (Json)

I have a call to a WebAPI with the following code:

var client = new HttpClient
{
    BaseAddress = new Uri("http://localhost:8490/")
};
var jObject = new JObject();
jObject.Add("paramA", paramA);
jObject.Add("paramB", paramB);
JArray jArr = JArray.FromObject(paramsGenericArr);
jObject.Add("paramC", jArr);
var content = new StringContent(jObject.ToString(), Encoding.UTF8, "application/json");
var result = await client.PostAsync("api/path/tofunc", content).ConfigureAwait(false);
result.EnsureSuccessStatusCode();

The ParamsGeneric class is an abstract type with 2 derived classes:

[DataContract]
public class ParamsTypeA : ParamsGeneric
{
    [DataMember]
    public long itemC {get; set;}
    public ParamsTypeA() :
                      base()
    {}
}

[DataContract]
public class ParamsTypeB : ParamsGeneric
{
    [DataMember]
    public long itemD {get; set;}
    public ParamsTypeB() :
                      base()
    {}
}

[DataContract]
[KnownType(typeof(ParamsTypeA))]
[KnownType(typeof(ParamsTypeB))]
public abstract class ParamsGeneric
{
    [DataMember]
    public long itemA { get; set; }
    [DataMember]
    public long itemB {get; set;}
    public ParamsGeneric() 
    {}
}

I suspect that I have a problem with the deserialization in the WebAPI:

public class ClientData
{
    public string paramA { get; set; }
    public string paramB { get; set; }
    public ParamsGeneric[] paramC { get; set; }
}

[HttpPost]
[Route("api/path/tofunc")]
public async Task<bool> DoStuffAsync(ClientData clientData)
{
    ....
}

I have a problem with the paramsGenericArr/paramC (which is of type ParamsGeneric[], and holds items of type ParamsTypeA & ParamsTypeB)

The WebAPI receives a blank array (ParamsGeneric[0]), along with the other parameters.

Help will be appriciated.

UPDATE

Even if I try to pass a single ParamsGeneric object instead of an array, I receive null instead of the object.

SOLUTION

var serializer = new JsonSerializer();
serializer.TypeNameHandling = TypeNameHandling.Auto;
JArray jArr = JArray.FromObject(paramsGenericArr, serializer);

Did the trick.

Upvotes: 5

Views: 3448

Answers (3)

cwap
cwap

Reputation: 11287

While inheritance in messages / json is definitely possible, IMHO; it's just too much of a hassle :)

Anyway, you can actually let Newtonsoft.Json handle the inheritance for you, by setting TypeNameHandling

// Allow inheritance in json payload
JsonSerializerSettings serializerSettings = GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings;
serializerSettings.TypeNameHandling = TypeNameHandling.All;

.. or just

serializerSettings.TypeNameHandling = TypeNameHandling.Auto;

.. depending on your needs.

This is the easy fix, which will work fine if it's an internal API or if you can guarantee you will always be in control of the clients. If you have external clients, I would go the 'override default model binder'-approach such as what is posted here "Deserialising Json to derived types in Asp.Net Web API" - or very strongly consider avoiding inheritance in the model of the API.

Upvotes: 3

Krunal Mevada
Krunal Mevada

Reputation: 1655

Try to pass data to your API as below

Dictionary<string, string> param = new Dictionary<string, string>();
param.Add("paramA", paramA);
param.Add("paramB", paramB);

HttpClient client = new HttpClient();
HttpFormUrlEncodedContent contents = new HttpFormUrlEncodedContent(param);
var result = await client.PostAsync(new Uri("http://localhost:8490/api/path/tofunc")
                                                                         , contents);
var reply = await result.Content.ReadAsStringAsync();
if (reply.IsSuccessStatusCode)
{ 
}

Hope this will help you.

Upvotes: 0

Siva Kumar Siddam
Siva Kumar Siddam

Reputation: 154

[HttpPost]
[Route("api/path/tofunc")]
public async Task<bool> DoStuffAsync([FromBody]ClientData clientData)
{
....
}

Please keep [FromBody] in the web api method, so that model binder will map your body data to parameter i.e clientData.

Upvotes: -1

Related Questions