2015-01-26 15 views
7

Sto utilizzando i tipi di record in un progetto F # che sto esponendo a un progetto C# WebApi. Per esempio:F #, Json, WebApi Serializzazione dei tipi di opzione

type Account = {Amount:float; Number:int; Holder:string} 

Sulla base this postale e this post, il JSON è serializaing correttamente.

{"Amount":100.0,"Number":1,"Holder":"Homer"} 

Tuttavia, quando aggiungo in un tipo di opzione per la cronaca,

type Account = {Amount:float; Number:int; Holder:string option } 

il JSON diventa scollata.

{"Amount":100.0,"Number":1,"Holder":{"Case":"Some","Fields":["Homer"]}} 

vorrei il JSON di guardare lo stesso del tipo di record non sia un'opzione con il serializzatore essere abbastanza intelligente per prendere i valori e metterli in/out l'opzione di tipo automatico.

Qualcuno ha creato un formattatore personalizzato a tale scopo? C'è qualcosa OOB che mi manca?

Grazie

risposta

5

Un convertitore Json.NET personalizzato che gestisce tipi di opzioni e un solo tipo sindacati discriminati esiste (o almeno pretende di, ho provato solo il tipo di caso dell'opzione). Può essere trovato here.

Usage:

let act = {Amount= 100.0; Number= 1; Holder= Some "Homer"} 
let json = JsonConvert.SerializeObject(act, new IdiomaticDuConverter()) 
+0

Come dovrei aggiungere questo alla WebApiConfig in un progetto C#? C'è un modo per aggiungere un convertitore a DefaultContractResolver? –

+0

NM -> capito. formatter.SerializerSettings.Converters.Add (new IdiomaticDuConverter()); –

11

ho provato il convertitore collegato nel altra risposta, e non mi piace l'uscita di altri tossicodipendenti che non erano Opzione. Invece, potresti decidere di cambiare solo il comportamento sul tipo di opzione piuttosto che tutte le DU.

Ho trovato questo convertitore che cambierà solo il comportamento per il tipo di opzione per il rendering null sull'opzione Nessuno, altrimenti il ​​valore. Il codice originale/informazioni sull'autore possono essere trovati here.

open System 
open Microsoft.FSharp.Reflection 
open Newtonsoft.Json 
open Newtonsoft.Json.Converters 

type OptionConverter() = 
    inherit JsonConverter() 

    override x.CanConvert(t) = 
     t.IsGenericType && t.GetGenericTypeDefinition() = typedefof<option<_>> 

    override x.WriteJson(writer, value, serializer) = 
     let value = 
      if value = null then null 
      else 
       let _,fields = FSharpValue.GetUnionFields(value, value.GetType()) 
       fields.[0] 
     serializer.Serialize(writer, value) 

    override x.ReadJson(reader, t, existingValue, serializer) =   
     let innerType = t.GetGenericArguments().[0] 
     let innerType = 
      if innerType.IsValueType then (typedefof<Nullable<_>>).MakeGenericType([|innerType|]) 
      else innerType   
     let value = serializer.Deserialize(reader, innerType) 
     let cases = FSharpType.GetUnionCases(t) 
     if value = null then FSharpValue.MakeUnion(cases.[0], [||]) 
     else FSharpValue.MakeUnion(cases.[1], [|value|]) 

Utilizzando il convertitore è lo stesso di altra risposta:

let json = JsonConvert.SerializeObject(myObj, new OptionConverter())