3

I have a model class Link which is deserialized with JSON.Net.

public class Link
{
    [JsonConstructor]
    internal Link(int id)
    {
        Id = id;
    }

    public int Id { get; internal set; }

    [JsonProperty("title")]
    public string Title { get; internal set; }

    [JsonProperty("description")]
    public string Description { get; internal set; }

... and so on

    public Avatar AuthorAvatar { get; internal set; }
}

Avatar contains three properties: DefaultImageUri, SmallImageUri, MediumImageUri. Is it possible to create Avatar object on Link object deserialization which would use: author_avatar, author_avatar_small, author_avatar_medium json fields?

2
  • I'm afraid I don't understand your question... Commented Dec 13, 2014 at 18:30
  • @t3chb0t i just want to AuthorAvatar be created from three "JsonProperty" - author_avatar, author_avatar_small, author_avatar_medium instead of having three Uri fields in Link class called: Uri AuthorAvatarDefault, Uri AuthorAvatarSmall, Uri AuthorAvatarMedium (i want to "pack" them into another class called Avatar) Commented Dec 13, 2014 at 18:58

2 Answers 2

4

I believe You can achieve this by writing your own JsonConverter here is an example (I omitted the serialization part, but the implementation would be very similar to De-serialization):

Sample:

class Program
{
    private static void Main(string[] args)
    {
        var json = @"{  
                        id:1,
                        title: 'link title',
                        description: 'link description',
                        author_avatar:'link',
                        author_avatar_small:'small link',
                        author_avatar_medium:'medium link',
                     }";

        var obj = JsonConvert.DeserializeObject<Link>(json);
    }
}

Class Definitions:

[JsonConverter(typeof(LinkSerializer))]
public class Link
{
    [JsonConstructor]
    public Link(int id)
    {
        Id = id;
    }

    [JsonIgnore]
    public int Id { get; internal set; }

    [JsonProperty("title")]
    public string Title { get; internal set; }

    [JsonProperty("description")]
    public string Description { get; internal set; }


    public Avatar AuthorAvatar { get; internal set; }
}

public class Avatar
{
    [JsonProperty("author_avatar")]
    public string DefaultImageUri { get; internal set; }
    [JsonProperty("author_avatar_small")]
    public string SmallImageUri { get; internal set; }
    [JsonProperty("author_avatar_medium")]
    public string MediumImageUri { get; internal set; }
}

Custom Link Serializer:

public class LinkSerializer : JsonConverter
{

    public override bool CanConvert(Type objectType)
    {
        return typeof (Link) == objectType;
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var jObject = JObject.Load(reader);

        //NOTE:I changed .ctor to publec to simplify the process, we can also check for JsonConstructor attribute on constructors and the call appropriate one
        var value = existingValue ?? Activator.CreateInstance(objectType, jObject["id"].Value<int>());
        Populate(objectType, jObject, value);

        var avatar = Activator.CreateInstance<Avatar>(); //Fill avatar object
        Populate(avatar.GetType(),jObject,avatar);

        objectType.GetProperty("AuthorAvatar").SetValue(value,avatar); //set avatar object

        return value;
    }

    private static void Populate(Type objectType, JObject jObject, object value)
    {
        var properties =
            objectType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

        foreach (var p in properties)
        {
            var ignore = p.GetCustomAttribute<JsonIgnoreAttribute>();
            if (ignore != null)
                continue;

            var custom = p.GetCustomAttribute<JsonPropertyAttribute>();
            var name = custom != null ? custom.PropertyName : p.Name;

            var token = jObject[name];
            var obj = token != null
                ? token.ToObject(p.PropertyType)
                : p.PropertyType.IsValueType ? Activator.CreateInstance(p.PropertyType) : null;

            p.SetValue(value, obj);
        }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        //we just want to deserialize the object so we don't need it here, but the implementation would be very similar to deserialization
    }
Sign up to request clarification or add additional context in comments.

Comments

2

Do you mean something like this?

class Program
{
    static void Main(string[] args)
    {

        string json =
        @"{
            Id: 1,
            author_avatar: 'abc',
            author_avatar_small: 'small',
            author_avatar_medium: 'medium'
        }";
        var link = JsonConvert.DeserializeObject<Link>(json);
    }
}

public class Link
{
    public Link(string author_avatar, string author_avatar_small, string author_avatar_medium)
    {
        AuthorAvatar = new Avatar(author_avatar, author_avatar_small, author_avatar_medium);
    }
    public int Id { get; set; }
    public Avatar AuthorAvatar { get; set; }
}

public class Avatar
{
    public Avatar(string author_avatar, string author_avatar_small, string author_avatar_medium)
    {
        DefaultImageUri = author_avatar;
        SmallImageUri = author_avatar_small;
        MediumImageUri = author_avatar_medium;
    }
    public string DefaultImageUri { get; set; }
    public string SmallImageUri { get; set; }
    public string MediumImageUri { get; set; }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.