Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Web Api 2 - custom data type JSON serialization

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?
like image 516
Usein Mambediiev Avatar asked Dec 20 '25 19:12

Usein Mambediiev


1 Answers

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

like image 179
Khanh TO Avatar answered Dec 22 '25 07:12

Khanh TO



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!