Search code examples
c#asp.net-web-apidatacontractserializer

Tweak and simplify DataContract serialization for very simple classes?


Suppose I have a type whose value can be fully represented by an integer but has validation logic, and it will be returned and accepted in Web API. In keeping with good code and avoiding primitive obsession, I might do something like:

public class FiscalPeriod
{
    public FiscalPeriod(int id)
    {
        if (!Validator.IsValidPeriod(id)) 
            throw new ArgumentException($"Invalid fiscal period ID '{id}'", nameof(id));
        Id = id;
    }

    public int Id { get; private set; }
    public override string ToString() => Id.ToString();
    public static implicit operator int(FiscalPeriod period) => period.Id;
}

Then, when this type is returned by a Web API call, it gets serialized into JSON as:

"FiscalPeriod" : {"Id": 201601},

Is there a way instead to force it to serialize to the following?

"FiscalPeriod" : 201601,

So that it can be more easily handled as a plain number on the client side?


Solution

  • You can tell Json.Net how to deal with the type using the JsonConverter attribute.

    public class ViewModel
    {
       public FiscalPeriod FiscalPeriod { get; set; }
    }
    
    public class FiscalPeriodConverter : JsonConverter
    {
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            var fiscalPeriod = value as FiscalPeriod;
            writer.WriteStartObject();
            serializer.Serialize(writer, fiscalPeriod.Id);
            writer.WriteEndObject();
        }
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }
    
        public override bool CanConvert(Type objectType)
        {
            return typeof(FiscalPeriod).IsAssignableFrom(objectType);
        }
    }
    
    [JsonConverter(typeof(FiscalPeriodConverter))]
    public class FiscalPeriod
    {
        public FiscalPeriod(int id)
        {
            if (!Validator.IsValidPeriod(id))
                throw new ArgumentException($"Invalid fiscal period ID '{id}'", nameof(id));
            Id = id;
        }
    
        public int Id { get; private set; }
        public override string ToString() => Id.ToString();
        public static implicit operator int(FiscalPeriod period) => period.Id;
    }
    

    http://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_JsonConverterAttribute.htm