3

I'm actually new to Web Api, so my question may sound a bit odd.

I have simple API to return historical information about price changes. My controller's action looks like this:

[HttpGet]
[Route("api/history/{id}/{size}")]
public async Task<IEnumerable<PriceHistoryRecordModel>> GetHistory(string id, Size size)

where PriceHistoryRecordModel is

[DataContract]
public class PriceHistoryRecordModel
{
    [DataMember]
    public DateTime Date { get; set; }

    [DataMember]
    public double Value { get; set; }
}

However, the problem is - action returns JSON in following format

[{"Date":"2016-02-07T08:22:46.212Z","Value":17.48},{"Date":"2016-02-08T09:34:01.212Z","Value":18.37}]

but, due to specific client requirements to data format, I need my JSON to look this way

[[1238371200000,17.48],[1238457600000,18.37]]

So, I wonder

  • if there's a way to achieve such custom serialization?
  • can I wrap this custom serialization in an attribute and use it as an aspect?
Usein Mambediiev
  • 243
  • 2
  • 11
  • 1
    Try changing your return type to `double[]`: `public async Task> GetHistory(string id, Size size)`. And covert your datetime to a number by using `DateTime.Millisecond` – Khanh TO Mar 26 '16 at 09:43
  • @KhanhTO Thanks, that worked and resolved the immediate problem. However, a question with custom serialization stays. – Usein Mambediiev Mar 26 '16 at 11:47

1 Answers1

5

You can write a CustomConverter like this:

public class CustomCoverter : JsonConverter
    {
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            PriceHistoryRecordModel obj = value as PriceHistoryRecordModel;
            JToken t = JToken.FromObject(new double[] { obj.Date.Ticks, obj.Value });
            t.WriteTo(writer);
        }

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

        public override bool CanConvert(Type objectType)
        {
            return typeof(PriceHistoryRecordModel).IsAssignableFrom(objectType);
        }
    }

Specify that our class is serialized by this converter:

[JsonConverter(typeof(CustomCoverter))]
[DataContract]
public class PriceHistoryRecordModel
{
    [DataMember]
    public DateTime Date { get; set; }

    [DataMember]
    public double Value { get; set; }
}

It works, but it's kind of overhead if you only need this special treatment in this specific case.

In case you have many similar cases like this, you can have your classes implement a base class and use this converter for all these classes.

In this simple case, a quick solution is just to change your return type to double[]:

public async Task<IEnumerable<double[]>> GetHistory(string id, Size size)

And covert your datetime to a number by using DateTime.Ticks

Khanh TO
  • 48,509
  • 13
  • 99
  • 115