繁体   English   中英

如何正确将 F# 记录序列化为 JSON?

[英]How to serialize F# records to JSON properly?

我在 F# 中有几种类型,例如:

  type ResourceRecordSet =
    | Alias of Name : string * 
        Type : ResourceRecordType * 
        AliasTarget : AliasTarget
    | Record of Name : string * 
        Type : ResourceRecordType *  
        ResourceRecords : List<string> * TTL : uint32

使用类型:

    let r = 
      Record(
        "domain.tld."
        , SOA
        , ["ns-583.awsdns-08.net. 
          awsdns-hostmaster.amazon.com. 
          1 7200 900 1209600 86400"]
        , 900u
      )

当我尝试将其序列化为 JSON 时,我得到以下信息:

let rjson = JsonSerializer.Serialize(r)
sprintf "%A" rjson

Output:

"{"Case":"Record","Fields":["doman.tld.",{"Case":"SOA"},["ns-583.awsdns-08.net. awsdns-hostmaster.amazon.com. 1 7200 900 1209600 86400"],900]}"

有没有办法控制序列化并产生以下内容:

{
  "Name": "doman.tld.",
  "ResourceRecords": [ {"Value": "ns-583.awsdns-08.net. awsdns-hostmaster.amazon.com. 1 7200 900 1209600 86400" }],
  "TTL": 900,
  "Type": "SOA"
}

为了回答我自己的问题,在阅读了不同人建议的不同库之后,Fleece 似乎是这里最可靠的解决方案。

首先是一个简单的例子:

open System.Text.Json
open Fleece.SystemTextJson
open Fleece.SystemTextJson.Operators
open FSharpPlus

  type AliasTarget =
    {
      DNSName               : string
      EvaluateTargetHealth  : bool
      HostedZoneId          : string
    }
    static member ToJson (a: AliasTarget) =
        jobj [
            "DNSName"               .= a.DNSName
            "EvaluateTargetHealth"  .= a.EvaluateTargetHealth
            "HostedZoneId"          .= a.HostedZoneId
        ]
    static member OfJson json =
        match json with
        | JObject o ->
            monad {
                let! dnsName = o .@ "DNSName"
                let! evaluateTargetHealth = o .@ "EvaluateTargetHealth"
                let! hostedZoneId = o .@ "HostedZoneId"
                return {
                    DNSName = dnsName
                    EvaluateTargetHealth = evaluateTargetHealth
                    HostedZoneId = hostedZoneId
                }
            }
        | x -> Decode.Fail.objExpected x

let outp = aliasTargetToJSON { DNSName = "dbrgct5gwrbsd.cloudfront.net."; EvaluateTargetHealth = false; HostedZoneId = "xxx"}
    loggerBlog.LogInfo outp
    let aliasJson = """{"DNSName":"dbrgct5gwrbsd.cloudfront.net.","EvaluateTargetHealth":false,"HostedZoneId":"xxx"}"""
    let alias : AliasTarget ParseResult = parseJson aliasJson
    loggerBlog.LogInfo (sprintf "%A" alias)

这打印:

2020-06-08T23:26:09 INFO [Website] {"DNSName":"dbrgct5gwrbsd.cloudfront.net.","EvaluateTargetHealth":false,"HostedZoneId":"xxx"}
2020-06-08T23:26:09 INFO [Website] Ok { DNSName = "dbrgct5gwrbsd.cloudfront.net."
     EvaluateTargetHealth = false
     HostedZoneId = "xxx" }

序列化和反序列化都有效。

也可以实施 ADT 或有区别的联合:

type Shape =
    | Rectangle of width : float * length : float
    | Circle of radius : float
    | Prism of width : float * float * height : float
    with 
        static member JsonObjCodec =
            Rectangle <!> jreq "rectangle" (function Rectangle (x, y) -> Some (x, y) | _ -> None)
            <|> ( Circle <!> jreq "radius" (function Circle x -> Some x | _ -> None) )
            <|> ( Prism <!> jreq "prism"   (function Prism (x, y, z) -> Some (x, y, z) | _ -> None) )

更多在这里:

https://github.com/fsprojects/Fleece

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM