SB2055
SB2055

Reputation: 12862

WebAPI not serializing inherited class on POST?

Here is my controller method:

    [System.Web.Http.HttpPost]
    [System.Web.Http.Route("api/exercise")]
    public HttpResponseMessage CreateExercise(ExerciseDto exercise) {

Here are my classes:

public class Exercise {

    [Key]
    [Required]
    public int ExerciseId { get; set; }

    [StringLength(300, ErrorMessage = "The value cannot exceed 300 characters. ")]
    public string Title { get; set; }

}

[NotMapped]
[Serializable]
public class ExerciseDto : Exercise {
    public ExerciseDto(Exercise exercise) {
        ExerciseId = exercise.ExerciseId;
        Title = exercise.Title;
        UserHasExercise = true;
    }
    public bool UserHasExercise { get; set; }
    public List<int> SomeIds { get; set; }
}

If I use type Exercise in the API controller, the object comes through. I created the DTO to extend the POCO with some more properties, but if I use this ExerciseDto class, I get null whenever I send the same data I was sending before. What is happening?

WebAPI Config:

        var json = config.Formatters.JsonFormatter;
        json.SerializerSettings.PreserveReferencesHandling = PreserveReferencesHandling.None;
        config.Formatters.Remove(config.Formatters.XmlFormatter);
        json.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
        config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
        var enumConverter = new Newtonsoft.Json.Converters.StringEnumConverter();
        json.SerializerSettings.Converters.Add(enumConverter);

Update:

My solution for the time being is to scrap the idea of DTOs altogether and just extend the POCO with [NotMapped] properties:

public class Exercise {

    [Key]
    [Required]
    public int ExerciseId { get; set; }

    [StringLength(300, ErrorMessage = "The value cannot exceed 300 characters. ")]
    public string Title { get; set; }

    [NotMapped]
    public bool UserHasExercise { get; set; }

    [NotMapped]
    public List<int> SomeIds { get; set; }

}

This keeps everything super simple, but I have a feeling it's not a best practice for more complicated models. Am very interested in seeing the proper way to handle this.

Upvotes: 1

Views: 2147

Answers (2)

John Hoerr
John Hoerr

Reputation: 8025

ExerciseDto needs a parameterless constructor in order for the Post body deserialize properly.

Update: your update is the way I would do it.

Upvotes: 3

djikay
djikay

Reputation: 10628

I believe the problem is that you've declared ExerciseDto as [Serializable] but you're not passing all ExerciseDto model parameters in your request (you mentioned that you pass the same data as you did for Exercise). You can either remove the [Serializable] attribute or, alternatively, add [JsonIgnore] to your model's UserHasExercise and SomeIds parameters. If you're passing the data as xml and not json, then use [IgnoreDataMember] instead of [JsonIgnore].

Upvotes: 0

Related Questions