簡體   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