Tarmil / FSharp.SystemTextJson

System.Text.Json extensions for F# types
MIT License
329 stars 45 forks source link

UnwrapOption and nullable-DateTimes #62

Open pseudoramble opened 4 years ago

pseudoramble commented 4 years ago

Thanks for the library! It's been very useful so far.

I think I'm just having a misunderstanding of how to configure the options properly. So if there's a better place to ask support-like questions, let me know.

I receive a response from another service which I then deserialize, examine it, and then serialize it back as a record. It looks like this:

{
    "deletedOn": "2020-06-27T16:47:18.660832Z"
}

This value can also be null, so I represent this as a DateTime option in the object I deserialze it to. When I serialize the record, I end up with a result like this:

{
    "deletedOn": {
        "value": "2020-06-27T16:47:18.660832Z"
    }
}

Is there a special setup I need to apply to make it so the result is "deletedOn": "2020-06-27T16:47:18.660832Z" instead? I thought that perhaps because DateTime is a value type it may need to be a voption<DateTime> but that did not seem to resolve it. So far I've tried to explicitly tell the converter to UnwrapOption types, as well as adding the JsonUnwrapValueOptionConverter explicitly to the options. Neither of those have worked.

pseudoramble commented 4 years ago

Of course after posting this I realized one of my mistakes by reading more carefully. Originally I was only using this converter inside one of my controllers. Since I'm using ASP.NET Core, I needed to apply this to all controllers so when the type is serialized in the response it actually uses it. This is in the docs already, but in case somebody else stumbles upon it, do this:

type Startup private () =
    new (configuration: IConfiguration) as this =
        Startup() then
        this.Configuration <- configuration

    member this.ConfigureServices(services: IServiceCollection) =
        services.AddControllers()
            .AddJsonOptions(fun options -> 
                options.JsonSerializerOptions.Converters.Add(JsonFSharpConverter())) 
        |> ignore

Though now I receive a different error:

System.Text.Json.JsonException: The JSON value could not be converted to Microsoft.FSharp.Core.FSharpOption`1[System.DateTime]. Path: $.deletedOn | LineNumber: 0 | BytePositionInLine: 507.
   at System.Text.Json.ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(Type propertyType)
   at System.Text.Json.JsonPropertyInfoNotNullable`4.OnRead(ReadStack& state, Utf8JsonReader& reader)
   at System.Text.Json.JsonPropertyInfo.Read(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
   at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
   at System.Text.Json.JsonSerializer.ReadCore(Type returnType, JsonSerializerOptions options, Utf8JsonReader& reader)
   at System.Text.Json.JsonSerializer.Deserialize(String json, Type returnType, JsonSerializerOptions options)
   at System.Text.Json.JsonSerializer.Deserialize[TValue](String json, JsonSerializerOptions options)

In the meantime, I've been able to modify the type to deletedOn: Nullable<DateTime>. That seems to let me work around my issue, but I think I should be able to use option instead. Any ideas on other things I should check?