I have an existing controller where [FromBody]
is working as expect in HttpPost
methods. When writing tests, I found it necessary to use a customer serializer in order to avoid a circular reference due to the parent object having a child that references the parent. The serializer uses these settings:
JsonSerializerSettings Settings = new JsonSerializerSettings()
{
TypeNameHandling = TypeNameHandling.Auto,
ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor,
PreserveReferencesHandling = PreserveReferencesHandling.Objects,
ObjectCreationHandling = ObjectCreationHandling.Auto
};
The problem is that [FromBody]
is unable to parse the object produced by that serializer (it throws a Newtonsoft.Json.JsonSerializationException). However, if I change [FromBody]
to be dynamic, e.g.
public IActionResult Update([FromBody]dynamic json)
{
var obj = Newtonsoft.Json.JsonConvert.DeserializeObject<MyType>(json);
...
}
then I'm able to parse the object without a problem. This is confusing me, and I am wondering if I can override what WebApi does for [FromBody]
so that I can get the correct object without having to make every method accept a dynamic
parameter?
Here is something I did in my WebAPI. I had a Team entity which has many Player entities. Each Player entity had a reference to a Team entity. When I retrieve a Player it will have a Team, and Team will have all players and each player again will have have a team in it.
To Handle this, I had to change the approach of exposing data and using the data. I created Models for each entities and exposed the model objects. Model objects are flat objects. In case of Player model, it has a TeamID and Team Name rather than using a whole Team object.
I used a Model-Factory to create Models out of Entities and Entities out of Models. In WebAPI controller, used something like below
[ModelValidator]
public IHttpActionResult Post([FromBody] DoctorModel doctorModel)
{
try
{
var doctorEntity = ModelFactory.Create(doctorModel);
doctorEntity.UserId = Userid;
var doctor = UnitOfWork.Doctors.Add(doctorEntity);
var doctorModelNew = ModelFactory.Create(doctor);
return Ok(doctorModelNew);
}
catch (Exception ex)
{
//Logging
#if DEBUG
return InternalServerError(ex);
#endif
return InternalServerError();
}
}