2

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?

riqitang
  • 3,241
  • 4
  • 37
  • 47
  • I assume you are using entities directly. I mean are you using same entities for your db operations and as api return type? – Sanish Joseph Jun 30 '17 at 07:53
  • That's right, and some of my APIs call other APIs so this kind of serialization/deserialization is important to me – riqitang Jun 30 '17 at 12:51

1 Answers1

1

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();
            }

        }
Sanish Joseph
  • 2,140
  • 3
  • 15
  • 28
  • You're saying to have the controllers use different models for API commands, and the services used by the controllers use the Entity Framework database models? That approach will probably work, I'm not going to mark the answer as accepted yet though, I want to see some other answers first. – riqitang Jul 05 '17 at 13:14