Ada Richards
Ada Richards

Reputation: 313

Deserialize object using JSON.NET, but put some properties into a member of the class

I am writing a set of data structures to ingest third-party JSON into (no writing out) using JSON.NET.

I have a case for reading some of the top-level JSON elements into a member object of the object being deserialized into.

My JSON:

{
    "Id":1
    "Checksum":42
    "Name":"adam",
    "Hair":true
}

My ideal object structure:

public class EntityHeader
{
    int Id { get; set; }

    int Checksum { get; set; }
}

public class Entity
{
    [HeroicJsonAttribute( "Id", "Checksum" )]
    public EntityHeader Header { get; set; }

    public string Name { get; set; }

    public bool Hair { get; set; }
}

Is there a simple way to achieve this? I will have a number of types which will need this, and I'd hate to have to write a JsonConverter for each.

This question has been asked before, here, but the accepted answer doesn't address the question.

Thanks!

Upvotes: 2

Views: 1193

Answers (3)

Stephen Byrne
Stephen Byrne

Reputation: 7485

I'm going to go ahead and post this answer which is a little bit too long for a comment, so please take this more as an extended comment than an actual attempt to answer your specific question. And of course, you know your requirements best so this is just my considered opinion :)

With that in mind, my advice is:

Don't do this.

  • I would instead create a simple DTO class that has a 1-1 relationship to the JSON being received; and I'd put all my validation attributes on the properties of that class.

  • Once I had deserialised the JSON into this simple DTO, I would then use a mapping layer of some kind (roll your own or use Automapper, etc) to map this DTO into a more meaningful structure such as your Entity class.

  • My reasoning behind this is because unless your Entity class is itself only a simple DTO (in which case it should be as simple as possible and ideally not be a composite) you are mixing OOP and concerns with data mapping concerns; whilst this in and of itself is not such a bad thing, it only serves to increase the complexity of your code.

  • Consider for example if your incoming JSON ends up with 30 or 40 properties, and you manage to figure out a way (maybe adapting some of the nice techniques from the other answers) to map it to the Entity class. But what about when something goes wrong - it's going to be much easier to reason about, and therefore debug, a process which you have much more control over; it's also going to be much easier to make special adaptations for odd edge cases where the serialiser behaviour just can't help you out

  • Granted it's a bit of work to write and maintain these DTOs but not that much - Webtools already does this for you

Reference: At the boundaries, Applications are not Object-Oriented

Upvotes: 1

Erik Philips
Erik Philips

Reputation: 54618

Base on your example you could either; use the adapter pattern:

public class EntityJson
{
  int Id { get; set; }

  int Checksum { get; set; }

  public string Name { get; set; }

  public bool Hair { get; set; }
}

// quick/poor example
public class EntityAdapter : IEntity
{
  public EntityAdapter(EntityJson model)
  {
    Header = new Header(); // and populate this objects fields
    Name = model.Name; // populate other properties
  }

  public EntityHeader Header { get; set; }

  public string Name { get; set; }

  public bool Hair { get; set; }

}

Or abuse the fact that json.net ignores properties not available:

var entity = JsonConvert.Deserialze<Entity>();
var header = JsonConvert.Deserialize<EntityHeader>();
entity.Header = header;

Upvotes: 1

Ada Richards
Ada Richards

Reputation: 313

An alternative approach would be to use an EntityHeader field in the Entity class as a backing store for private properties which can be deserialized into:

public class EntityHeader
{
    int Id { get; set; }

    int Checksum { get; set; }
}

public class Entity
{
    private EntityHeader m_Header = new EntityHeader();
    public EntityHeader Header { get { return m_Header; } }

    [JsonProperty]
    private int Id { set { m_Header.Id = value; } }

    [JsonProperty]
    private int Checksum { set { m_Header.Checksum = value; } }

    public string Name { get; set; }

    public bool Hair { get; set; }
}

Thus, all the properties in the JSON can be read straight into the Entity object, but consumers of Entity objects have access to a "nicely encapsulated" EntityHeader property.

I haven't tested this, and it may even be kludgey, but it would technically work for me (OP). I am still interested in other answers!

Upvotes: 1

Related Questions