I'm running across an issue when I define a field of option type while serializing for JSON.
Before works (without option)
[<DataContract>]
type Article = {
[<field: DataMemberAttribute(Name="version") >]
version: string
}
After throws error (with option)
[<DataContract>]
type Article = {
[<field: DataMemberAttribute(Name="version") >]
version: string option
}
method threw exception:
System.Runtime.Serialization.SerializationException: Expecting state 'Element'.. Encountered 'Text' with name '', namespace ''.
Related Code
let response = request.GetResponse() :?> HttpWebResponse
use reader = new StreamReader(response.GetResponseStream())
use memoryStream = new MemoryStream(ASCIIEncoding.Default.GetBytes(reader.ReadToEnd()))
let result = (new DataContractJsonSerializer(typeof<Article>)).ReadObject(memoryStream) :?> Article
Here is a definition with a nullable int. String can already be null to which the zillions of Null reference exceptions attest...
open System
[<DataContract>]
type Person2 = {
[<DataMember(Name="Name") >]
entityName: Nullable<int>
[<DataMember(Name="Type") >]
entityType: String
}
However if you plan to fill this with a bunch of nulls maybe you should consider a class. This is really horrible but here's how it looks:
let p1 = { entityName = Nullable(10); entityType = "John"}
let p2 = { entityName = System.Nullable(); entityType = null}
val p1 : Person2 = {entityName = 10;
entityType = "John";}
val p2 : Person2 = {entityName = null;
entityType = null;}
Related
Is there any way to force parsing of only non-empty string fields of a record type in F# using Newtonsoft.Json?
#r """Newtonsoft.Json.dll"""
open Newtonsoft.Json
type Customer = {
Name: string
Email: string
ContactPhoneNo: string
}
// one or more fields can be empty
let customer = {
Name = ""
Email = "ca#gmail.com"
ContactPhoneNo = "+123456789"
}
let serializedCustomer =
JsonConvert.SerializeObject(customer)
// this parses correctly with the Name field set as ""
// But as the name field is empty, it should not parse it
let deserializedCustomer =
JsonConvert.DeserializeObject<Customer>(serializedCustomer)
You might want to consider using Newtonsoft's schema support for this, which is in a separate package called Newtonsoft.Json.Schema. You can specify many different kinds of constraints using annotations. For example, to disallow blank names, you can use MinLength:
open System.ComponentModel.DataAnnotations
type Customer = {
[<MinLength(1)>]
Name: string
Email: string
ContactPhoneNo: string
}
Once you've annotated your type, you can generate a schema:
let generator = JSchemaGenerator()
let schema = generator.Generate(typeof<Customer>)
Then use it to validate the serialized JSON:
let jsonCustomer = JObject.Parse(serializedCustomer)
let isValid = jsonCustomer.IsValid(schema)
If you want to skip the overhead of first loading JSON into a JObject in order to validate it, you can use a JSchemaValidatingReader instead:
use strReader = new System.IO.StringReader(serializedCustomer)
use txtReader = new JsonTextReader(strReader)
use vldReader = new JSchemaValidatingReader(txtReader, Schema = schema)
let messages = ResizeArray()
vldReader.ValidationEventHandler.Add(fun args -> messages.Add(args.Message))
let serializer = JsonSerializer()
let deserializedCustomer = serializer.Deserialize<Customer>(vldReader)
printfn "%A" deserializedCustomer
let isValid = (messages.Count = 0)
printfn "%A" isValid
See this documentation for details.
You could implement a custom JsonConverter that converts values of type string, but throws an exception when the string is empty:
let nonEmptyStringConverter =
{ new JsonConverter() with
override x.CanConvert(objectType) = objectType = typeof<string>
override x.WriteJson(writer, value, serializer) =
JValue(value :?> string).WriteTo(writer)
override x.ReadJson(reader, objectType, existingValue, serializer) =
let jt = JToken.Load(reader)
if jt.Type = JTokenType.String then
let str = jt.Value<string>()
if String.IsNullOrEmpty str then failwith "Empty string"
box str
else failwith "Expected a string" }
If you pass this to DeserializeObject, then it will throw an exception in your example:
let serializedCustomer =
JsonConvert.SerializeObject(customer)
let deserializedCustomer =
JsonConvert.DeserializeObject<Customer>(serializedCustomer, nonEmptyStringConverter)
One caveat is that this will apply to all string values in the type and I expect you may want to allow empty values for some. A better approach would be to define a custom type and define a convertor only for this type, e.g. using:
type NonEmptyString = NE of string
type Customer =
{ Name : NonEmptyString
Email: NonEmptyString
ContactPhoneNo: string }
I'm working on a new system where I am using strongly typed Id values for my entities. To do that, I've followed a pattern that I've seen recommended before. The code seems very repetitive though and I'd like to simplify it.
type PersonId = private PersonId of string
module PersonId =
let private prefix = "person"
let value (PersonId id) = id
let create (id: string) = PersonId(sprintf "%s_%s" prefix id)
type OrderId = private OrderId of string
module OrderId =
let private prefix = "order"
let value (OrderId id) = id
let create (id: string) = OrderId(sprintf "%s_%s" prefix id)
Is there a way to make this code more generic so I don't have to repeat the module code? I was thinking of making an EntityId discriminated union of the PersonId and OrderId type, but not sure what the EntityId module code might look like. Thanks for the help.
I think you're headed towards something like this:
type EntityId =
private
| PersonId of string
| OrderId of string
module EntityId =
let init makeEntity prefix =
fun id -> makeEntity (sprintf "%s_%s" prefix id)
let value = function
| PersonId id
| OrderId id -> id
The trick here is that the init function is used to make your current create functions, like this:
module PersonId =
let create = EntityId.init PersonId "person"
module OrderId =
let create = EntityId.init OrderId "order"
And then you can use it like this:
let personId = PersonId.create "abc"
let orderId = OrderId.create "xyz"
printfn "%A" personId
printfn "%A" orderId
printfn "%s" <| EntityId.value personId
printfn "%s" <| EntityId.value orderId
Output is:
PersonId person_abc
OrderId order_xyz
person_abc
order_xyz
P.S. If you like currying, you can simplify init to:
let init makeEntity prefix id =
makeEntity (sprintf "%s_%s" prefix id)
My intent is to define a module with functions which can operate on all records types which comply with certain assumptions about the keys.
To illustrate, let us have the following code:
> type DBRow = { id: string ; createdAt: System.DateTime } ;;
type DBRow =
{id: string;
createdAt: System.DateTime;}
> let logCreationInfo row = printf "Record %s created at %s " row.id (row.createdAt.ToString()) ;;
val logCreationInfo : row:DBRow -> unit
I would like to change the above logCreationInfo to be able to operate on all records which have id: string and createdAt: System.DateTime (and maybe other things).
Coming from typescript's structural typing, I'd have expected this to be trivial, but I am exploring the possibility that there is a more idiomatic way to handle this in F#.
I had attempted to handle this using interfaces, but even if that could work, since F# supports only explicit interfaces, this will not be suitable for types I don't define myself.
You could use statically resolved type constraints.
let inline logCreationInfo (x : ^t) =
printfn "Record %s created at %s"
(^t : (member id : string) (x))
((^t : (member createdAt : System.DateTime) (x)).ToString())
F# largely uses nominative typing - this is a natural choice in its runtime environment, as this is what Common Type System specification prescribes. Adherence to that set of rules allows F# code to near-seamlessly interoperate with other .NET languages.
It's worth noting that this follows the same reasoning as to why TypeScript uses structural typing. Since that language builds up on top of dynamically typed JavaScript, it's more natural to express object relationships in terms of their structure rather than nominal types - which are a foreign concept in JS.
F# does have a "backdoor" for structural typing through already mentioned SRTPs, but I would suggest using it very sparingly. SRTPs are resolved and the code using them is inlined by the compiler, making for longer compilation times and reduced interoperability with other languages and the .NET platform in general (simply put, you can't refer to that code from other languages or using reflection API, because it's "compiled away").
Usually there are other solutions available. Interfaces were already mentioned, though the example used was a bit contrived - this is simpler:
type IDBRow =
abstract Id: string
abstract CreatedAt: System.DateTime
type Person =
{
id: string
name: string
age: int
createdAt: System.DateTime
}
interface IDBRow with
member this.Id = this.id
member this.CreatedAt = this.createdAt
let logCreationInfo (row: #IDBRow) =
printf "Record %s created at %s" row.Id (string row.CreatedAt)
let x = { id = "1"; name = "Bob"; age = 32; createdAt = DateTime.Now }
logCreationInfo x
Or using composition and a generic type to capture the generic part of what it means to be a DBRow:
type DBRow<'data> =
{
id: string
data: 'data
createdAt: System.DateTime
}
type Person =
{
name: string
age: int
}
let logCreationInfo (row: DBRow<_>) =
printf "Record %s created at %s" row.id (string row.createdAt)
let x = { id = "1"; data = { name = "Bob"; age = 32 }; createdAt = DateTime.Now }
logCreationInfo x
Here's a version with interfaces:
open System
type DBRow1 = {
id: string
createdAt: DateTime
}
type DBRow2 = {
id: string
createdAt: DateTime
address: string
}
/// The types are defined above without an interface
let row1 = {id = "Row1"; createdAt = DateTime.Now}
let row2 = {id = "Row2"; createdAt = DateTime.Now; address = "NYC"}
type IDBRow<'A> =
abstract member Data:(string * DateTime)
// Object expression implements the interface
let Data1 (x:DBRow1) = {
new IDBRow<_> with
member __.Data = (x.id, x.createdAt)
}
let Data2 (x: DBRow2) = {
new IDBRow<_> with
member __.Data = (x.id, x.createdAt)
}
//pass in both the object expression and the record
let getData (ifun: 'a -> IDBRow<'b>) xrec =
(ifun xrec).Data
// You could partially apply the functions: `getData1 = getData Data1`
getData Data1 row1 //("Row1", 2018/02/05 9:24:17)
getData Data2 row2 //("Row2", 2018/02/05 9:24:17)
You can certainly use an interface (an object expression in this case) to tack on another member, .Data, even if you don'T have access to the original type. You would still need to put together one object expression for each type though, so SRTP might be a more "elegant" solution.
I define a property in a class like:
type Customer() =
let mutable _lastName = String.Empty
member val LastName = _lastName with get
And in the method QueryData I assign a value to _lastName:
member self.QueryData () =
// CODE
let addressData = bp.GetStructure("PE_PERSONALDATA")
_lastName <- addressData.GetString("LASTNAME")
null
| RfcCommunication ex ->
let basedComm = ex :> Exception
basedComm
| RfcLogon ex ->
let basedLogon = ex :> Exception
basedLogon
| RfcAbapRuntime ex ->
let basedAbap = ex :> Exception
basedAbap
In the main function I created an instance of Customer() and read the LastName property:
[<EntryPoint>]
let main argv =
let customer = CustomerBapi.Customer()
let ex = customer.QueryData()
if ex <> null then printfn "%s" ex.Message
printfn "%s" customer.LastName
The result is empty string. I tried to debug the program and see that _lastName is not empty
Why is the LastName property is empty?
Your property should look like this:
member this.LastName with get () = _lastName
The type of property you are using is passing _lastName as the value to initialise it with.
Explanation from MSDN:
Private values that hold the data for properties are called backing
stores. To have the compiler create the backing store automatically,
use the keywords member val, omit the self-identifier, then provide an
expression to initialize the property. If the property is to be
mutable, include with get, set. For example, the following class type
includes two automatically implemented properties. Property1 is
read-only and is initialized to the argument provided to the primary
constructor, and Property2 is a settable property initialized to an
empty string:
type MyClass(property1 : int) =
member val Property1 = property1
member val Property2 = "" with get, set
I'm writing a generic class that has two constructors: the first one initializes every field, the second (parameter-less) should not initialize anything.
The only way I found to achieve this is calling the main constructor with "empty" arguments, i.e. Guid.Empty and null. Besides not looking good functional style to my untrained eyes, this means that I have to put a a' : null constraint on the second parameter, which I don't want:
type Container<'a when 'a : null>(id : Guid, content : 'a) =
let mutable _id = id
let mutable _content = content
new() = Container<'a>(Guid.Empty, null)
member this.Id
with get() = _id
and set(value) = _id <- value
member this.Content
with get() = _content
and set(value) = _content <- value
I see two ways to solve this:
use something like the default c# keyword instead of null (does such a thing exist in F#?)
use a different syntax to specify constructors and private fields (how?)
What is the best way to implement this class?
The F# analog to default is Unchecked.default<_>. It is also possible to use explicit fields which you don't initialize:
type Container<'a>() =
[<DefaultValue>]
val mutable _id : Guid
[<DefaultValue>]
val mutable _content : 'a
new (id, content) as this =
new Container<'a>() then
this._id <- id
this._content <- content
However, in general, your overall approach is somewhat unidiomatic for F#. Typically you'd use a simple record type (perhaps with a static method to create uninitialized containers, although this seems to have questionable benefit):
type 'a Container = { mutable id : Guid; mutable content : 'a } with
static member CreateEmpty() = { id = Guid.Empty; content = Unchecked.defaultof<_> }
In many situations, you could even use an immutable record type, and then use record update statements to generate new records with updated values:
type 'a Container = { id : Guid; content : 'a }
[<GeneralizableValue>]
let emptyContainer<'a> : 'a Container =
{ id = Guid.Empty;
content = Unchecked.defaultof<_> }
let someOtherContainer = { emptyContainer with content = 12 }
If the type will be used from languages other than F#, the following provides a natural interface in F#, and C#, for example.
type Container<'a>(?id : Guid, ?content : 'a) =
let orDefault value = defaultArg value Unchecked.defaultof<_>
let mutable _id = id |> orDefault
let mutable _content = content |> orDefault
new() = Container(?id = None, ?content = None)
new(id : Guid, content : 'a) = Container<_>(?id = Some id, ?content = Some content)
member this.Id
with get() = _id
and set(value) = _id <- value
member this.Content
with get() = _content
and set(value) = _content <- value
If it will only be used from F#, you can omit the following constructor overloads
new(id : Guid, content : 'a) = Container<_>(?id = Some id, ?content = Some content)
new() = Container()
because the overload accepting optional args handles both these cases equally well in F#.