F#, Json.NET 6.0 and WebApi - serialization of rec

2020-01-29 08:52发布

问题:

Json.NET 6.0.1 adds F# support for records and discriminated unions. When serializing a F# record type using Json.NET I now get nicely formatted JSON.

The serialization is done as follow:

let converters = [| (new StringEnumConverter() :> JsonConverter) |]
JsonConvert.SerializeObject(questionSet, Formatting.Indented, converters)

However, when I try to expose my F# types through a ASP.NET WebApi 5.0 service, written in C#, the serialized JSON includes an @-sign infront of all properties. The @-sign comes from the internal backing field for the record type (this used to be a known problem with Json.Net and F#).

But - since I'm using the updated version of Json.NET, shouldn't the result be the same as when calling JsonConvert? Or is JsonConvert behaving differently than JsonTextWriterand JsonTextReader?

As far as I can tell from reading the JsonMediaTypeFormatter in the WebApi source JsonTextWriterand JsonTextReader is used by WebApi.

回答1:

You can adorn your records with the [<CLIMutable>] attribute:

[<CLIMutable>]
type MyDtr = {
    Message : string
    Time : string }

That's what I do.


For nice XML formatting, you can use:

GlobalConfiguration.Configuration.Formatters.XmlFormatter.UseXmlSerializer <- true

For nice JSON formatting, you can use:

config.Formatters.JsonFormatter.SerializerSettings.ContractResolver <-
    Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver()


回答2:

I believe it's because the backing fields that are emitted by F# records don't follow the same naming convention as C# property backing fields.

The easiest way I've found to get around this is to change the ContractResolver at the startup of your web application from the System.Net.Http.Formatting.JsonContractResolver to use the Newtonsoft.Json.Serialization.DefaultContractResolver instead: -

Formatters.JsonFormatter.SerializerSettings.ContractResolver <- DefaultContractResolver()

You'll then get all JSON formatting done via Newtonsoft's JSON formatter rather than the NET one.