1

I have an object:

[JsonConverter(typeof(MessageConverter))]
public class Message
{
    [JsonProperty(Order = 1)]
    public long Id { get; set; }
    [JsonProperty(Order = 2)]
    public string Msg { get; set; }
    [JsonProperty(Order = 3)]
    public int Timestamp { get; set; }
}

Which I would like to serialise into an array in JSON of the following form:

[long, string, int]

This class would be nested in a hierarchy, so automatic conversion would be preferred.

I am currently using the following code, but this seems to contain a significant amount of repetition.

I was wondering if there were an attribute/more compact solution that would allow JSON.NET to use the provided attributes to provide the same functionality without the converter.

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

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var arr = serializer.Deserialize<JToken>(reader) as JArray;

        if (arr == null || arr.Count != 3)
            throw new JsonSerializationException("Expected array of length 3");

        return new Message
        {
            Id = (long)arr[0],
            Msg = (string)arr[1],
            Timestamp = (int)arr[2]
        };
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var msg = value as Message;
        var obj = new object[] { msg.Id, msg.Msg, msg.Timestamp };
        serializer.Serialize(writer, obj);
    }
}

2 Answers 2

1

If you are looking for that particular output, I don't think you'll find a cleaner solution than what you have. If your real goal is to serialize JSON in a compact way, look to standards like BSON or ProtoBuf

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you, I am looking for compactness of code rather than compactness of output. It looks possible for a general solution to exist, so I'll probably end up coding my own. I'll wait a while longer then accept your answer for the time-being.
yeah if you dont need this exact output, using a protobuf or bson library would also reduce your code since the general solution will be in that lib
1

This should do your job. I just wrote for WRITE i.e. output.

namespace Test
{
    using Newtonsoft.Json;
    using Newtonsoft.Json.Linq;
    using System;
    using System.Collections;
    using System.Reflection;

    /// <summary>
    /// Defines the custom JSON Converter of collection type that serialize collection to an array of ID for Ember.
    /// </summary>
    public class CustomConverter : JsonConverter
    {
        /// <summary>
        /// Define the property name that is define in the collection type.
        /// </summary>
        private readonly string IDKEY = "Id";

        private readonly string MSGKEY = "Msg";

        private readonly string TIMEKEY = "Timestamp";

        /// <summary>
        /// It is write only convertor and it cannot be read back.
        /// </summary>
        public override bool CanRead
        {
            get { return false; }
        }

        /// <summary>
        /// Validate that this conversion can be applied on IEnumerable type only.
        /// </summary>
        /// <param name="objectType">type of object</param>
        /// <returns>Validated value in boolean</returns>
        public override bool CanConvert(Type objectType)
        {
            return objectType == typeof(Message);
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
            JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Write JSON data from IEnumerable to Array.
        /// </summary>
        /// <param name="writer">JSON Writer</param>
        /// <param name="value">Value of an object</param>
        /// <param name="serializer">JSON Serializer object</param>
        public override void WriteJson(JsonWriter writer, object item, JsonSerializer serializer)
        {
            JArray array = new JArray();
            PropertyInfo prop = item.GetType().GetProperty(IDKEY);
            if (prop != null && prop.CanRead)
            {
                array.Add(JToken.FromObject(prop.GetValue(item, null)));
            }

            prop = item.GetType().GetProperty(MSGKEY);
            if (prop != null && prop.CanRead)
            {
                array.Add(JToken.FromObject(prop.GetValue(item, null)));
            }

            prop = item.GetType().GetProperty(TIMEKEY);
            if (prop != null && prop.CanRead)
            {
                array.Add(JToken.FromObject(prop.GetValue(item, null)));
            }


            array.WriteTo(writer);
        }
    }
}

You are telling JSON.NET that you want to use custom convertor. so where ever you want to use it, you will have to call through attribute.

I am also doing something similar and I have to call converter manually.

  /// <summary>
        /// Gets or sets collection of documents.
        /// </summary>
        [JsonConverter(typeof(IDWriteListConverter))]
        public ICollection<Document> Documents { get; set; }

        /// <summary>
        /// Gets or sets collection of comments.
        /// </summary>
        [JsonConverter(typeof(IDWriteListConverter))]
        public ICollection<Comment> Comments { get; set; }

        /// <summary>
        /// Gets or sets the collection of transactions.
        /// </summary>
        [JsonConverter(typeof(IDWriteListConverter))]
        public virtual ICollection<Transaction> Transactions { get; set; }

2 Comments

This doesn't answer my question at all. A working converter has already been supplied in the OP which provides more functionality with less code.
there is no inbuilt functionality.

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.