在 F# 中使用 newtonsoft 反序列化记录类型时如何禁止空字符串?
How to disallow empty string when deserializing record types with newtonsoft in F#?
有什么方法可以使用 Newtonsoft.Json 强制仅解析 F# 中记录类型的非空字符串字段?
#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)
您可以实现自定义 JsonConverter
来转换 string
类型的值,但在字符串为空时抛出异常:
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" }
如果您将其传递给 DeserializeObject
,那么它会在您的示例中抛出异常:
let serializedCustomer =
JsonConvert.SerializeObject(customer)
let deserializedCustomer =
JsonConvert.DeserializeObject<Customer>(serializedCustomer, nonEmptyStringConverter)
需要注意的是,这将适用于类型中的所有 string
值,我希望您可能希望为某些值允许空值。更好的方法是定义自定义类型并仅为该类型定义转换器,例如使用:
type NonEmptyString = NE of string
type Customer =
{ Name : NonEmptyString
Email: NonEmptyString
ContactPhoneNo: string }
您可能需要考虑为此使用 Newtonsoft 的模式支持,它位于一个名为 Newtonsoft.Json.Schema
的单独包中。您可以使用注释指定多种不同类型的约束。例如,要禁止空白名称,您可以使用 MinLength
:
open System.ComponentModel.DataAnnotations
type Customer = {
[<MinLength(1)>]
Name: string
Email: string
ContactPhoneNo: string
}
一旦你注释了你的类型,你就可以生成一个模式:
let generator = JSchemaGenerator()
let schema = generator.Generate(typeof<Customer>)
然后用它来验证序列化JSON:
let jsonCustomer = JObject.Parse(serializedCustomer)
let isValid = jsonCustomer.IsValid(schema)
如果您想跳过首次将 JSON 加载到 JObject
中以验证它的开销,您可以改用 JSchemaValidatingReader
:
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
有什么方法可以使用 Newtonsoft.Json 强制仅解析 F# 中记录类型的非空字符串字段?
#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)
您可以实现自定义 JsonConverter
来转换 string
类型的值,但在字符串为空时抛出异常:
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" }
如果您将其传递给 DeserializeObject
,那么它会在您的示例中抛出异常:
let serializedCustomer =
JsonConvert.SerializeObject(customer)
let deserializedCustomer =
JsonConvert.DeserializeObject<Customer>(serializedCustomer, nonEmptyStringConverter)
需要注意的是,这将适用于类型中的所有 string
值,我希望您可能希望为某些值允许空值。更好的方法是定义自定义类型并仅为该类型定义转换器,例如使用:
type NonEmptyString = NE of string
type Customer =
{ Name : NonEmptyString
Email: NonEmptyString
ContactPhoneNo: string }
您可能需要考虑为此使用 Newtonsoft 的模式支持,它位于一个名为 Newtonsoft.Json.Schema
的单独包中。您可以使用注释指定多种不同类型的约束。例如,要禁止空白名称,您可以使用 MinLength
:
open System.ComponentModel.DataAnnotations
type Customer = {
[<MinLength(1)>]
Name: string
Email: string
ContactPhoneNo: string
}
一旦你注释了你的类型,你就可以生成一个模式:
let generator = JSchemaGenerator()
let schema = generator.Generate(typeof<Customer>)
然后用它来验证序列化JSON:
let jsonCustomer = JObject.Parse(serializedCustomer)
let isValid = jsonCustomer.IsValid(schema)
如果您想跳过首次将 JSON 加载到 JObject
中以验证它的开销,您可以改用 JSchemaValidatingReader
:
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