Search code examples
c#jsonf#option-type

JSON deserialization: input DateTime? to output Option<DateTime>


Context:

one type has two representations: one in C# and one in F#. Value of the C# type gets serialized to json and then deserialized into a value of the F# type.

Is there a straightforward way to convert null json properties to Option<> F# values?

I'm facing a situation where null C# DateTime? UpdatedDate property gets serialized to json and then is expected to be deserialized into an FSharpOption<DateTime> UpdatedDate value (F# type, C# code, long story...) which breaks the code.

My json looks like this:

{
  "Property1": "1",
  "UpdatedDate": null,
  "Property2": "2"
}

I technically could deserialize my json to the C# type containing DateTime? UpdatedDate and then map the resulting value to the F# type containing FSharpOption<DateTime> UpdatedDate, but surely there must be a better way...


EDIT:

To deserialize json I'm using Newtonsoft's JsonConvert.DeserializeObject and .NET 5 + C# 9.


Solution

  • Ok, I figured it out thanks to the example @brianberns shared. Sample code:

    public class DummyJsonConverter : JsonConverter<FSharpOption<DateTime>>
    {
        public override FSharpOption<DateTime> Read(
            ref Utf8JsonReader reader,
            Type typeToConvert,
            JsonSerializerOptions options) =>
            FSharpOption<DateTime>.None;
    
        public override void Write(
            Utf8JsonWriter writer,
            FSharpOption<DateTime> dateTimeValue,
            JsonSerializerOptions options) =>
            writer.WriteStringValue("");
    }
    

    Usage:

    var serializerOptions = new JsonSerializerOptions();
    
    serializerOptions.Converters.Add(new DummyJsonConverter());
    
    var whoisResponses = JsonSerializer.Deserialize<SharedSupport.Models.Whois.WhoisResponseV2[]>(
        snsMessage.Message,
        serializerOptions);
    

    The only caveat is that I replaced the Newtonsoft serializer with the System.Text.Json serializer (JsonSerializer).


    EDIT:

    Following @ruben-bartelink's advice, I used the proposed nuget (FsCodec.NewtonsoftJson) instead of my own custom converter. The code is much simpler now that I don't have to worry about writing my own conversion. Additionally, I don't have to switch to System.Text.Json.

    var jsonSerializerSettings = new JsonSerializerSettings();
    
    jsonSerializerSettings.Converters.Add(new OptionConverter());
    
    var whoisResponses = JsonConvert.DeserializeObject<SharedSupport.Models.Whois.WhoisResponseV2[]>(
        snsMessage.Message,
        jsonSerializerSettings);