简体   繁体   中英

Handling Master Data on (De-)Serialization with JSON.net

Using JSON.NET I am stuck on a issue with MasterData with regards to GET and POST operations.

Using the example of a movie, the JSON I could get on a GET operation before deserializing is the following:

{
     “movie”: {
         “name”:”bad boys”,
         ”genre”: {
            “id”:"1",
            ”name”:”thriller”
        }
    }
}

However, on a POST operation I would like to construct a serialized string like the following:

{
     “movie”: {
         “name”:”bad boys”,
         ”genre”:"1"
    }
}

As you can see, with a GET operation I need to deserialize the complete object, while on serialize for POST I need to add the Id only, but with the same JsonPropertyName.

What is the cleanest way to obtain this situation? I've been trying to work on the IContractResolver and IReferenceResolver, but those both didn't get me there yet. Also have been trying to work with propertynames as the following example:

[JsonProperty(PropertyName = "genre")]
public Genre Genre { get; set; }

[JsonProperty(PropertyName = "genre")]
public string GenreId { get { return Genre != null ? Genre.Id : 0; } }

I've also tried using the ShouldSerialize[MemberName] and ShouldDeserialize[MemberName] situations, but those gave an exception saying I cannot use two properties with the same name, which is logical in a way.

For now, my only idea left is to use a DTO for serialization, but I would rather prefer something more clean than that solution. So open for suggestions!

You can write a Custom converter.

public class GenreConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(Genre);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        return JObject.Load(reader).ToObject<Genre>();
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var genre = value as Genre;
        writer.WriteValue(genre.id);
    }
}

All you need now is using JsonConverter atttribute

public class Movie
{
    public string Name { get; set; }
    [JsonConverter(typeof(GenreConverter))]
    public Genre Genre { get; set; }
}

Use custom converter for this. You want to check type of genre attribute and read it as object or int .

In my opinion, using a DTO is the cleanest solution. Since your models are different for GET/POST, you ideally require two separate models. I've abused the NullValueHandling.Ignore serializer setting to mean you can use the same model for both situations, providing you don't mind always having the Id property on Genre :

class MovieJsonWrapper
{
    [JsonProperty("movie")]
    public Movie Movie { get; set; }
}

class Movie
{
    [JsonProperty("name")]
    public string Name { get; set; }

    [JsonProperty("genre")]
    public Genre Genre { get; set; }
}

class Genre
{
    [JsonProperty("id")]
    public string Id { get; set; }

    [JsonProperty("name")]
    public string Name { get; set; }
}

We can then use this with:

var movie = new Movie
{
    Name = "bad boys",
    Genre = new Genre
    {
        Id = "1"
    }
};

var movieJsonWrapper = new MovieJsonWrapper { Movie = movie };

var jsonSerializerSettings = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore };

var json = JsonConvert.SerializeObject(movieJsonWrapper, jsonSerializerSettings);

Which would produce the following:

{
  "movie": {
    "name": "bad boys",
    "genre": {
      "id": "1"
    }
  }
}

Similarly, we can then deserialize the GET response with:

var result = JsonConvert.DeserializeObject<MovieJsonWrapper>(raw);

If you really do need to ditch the Id property on the Genre when POSTing, then you would require additional Models. This solution reduces the amount of boilerplate.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM