修复 JSON 中的数组返回
Fix Array in JSON Returned
我正在通过 LightSpeed 呼叫联系人 API。
当我打电话询问客户“A”的详细信息时,JSON 包含他的相关电子邮件的以下内容
{
"Emails": {
"ContactEmail": {
"address": "clienta@yahoo.com",
"useType": "Primary"
}
}
}
当我要求客户“B”的详细信息时,JSON 包含此相关电子邮件的以下内容
{
"Emails": {
"ContactEmail": [{
"address": "clientb1@gmail.com",
"useType": "Primary"
}, {
"address": "clientb2@gmail.com",
"useType": "Secondary"
}
]
}
}
如果我是对的,我相信第一个响应应该是一个数组,即使只返回了 1 个“电子邮件”...?因为系统允许客户在他们的记录中有超过 1 封电子邮件。
这是我要反序列化的 class。它对客户端“B”非常有效,但对客户端“A”无效
public class GetCustomersResponse
{
public Attributes attributes { get; set; }
public List<Customer> Customer { get; set; }
}
public class Attributes
{
public string count { get; set; }
}
public class Customer
{
public string customerID { get; set; }
public string firstName { get; set; }
public string lastName { get; set; }
public string title { get; set; }
public string company { get; set; }
public string companyRegistrationNumber { get; set; }
public string vatNumber { get; set; }
public DateTime createTime { get; set; }
public DateTime timeStamp { get; set; }
public string archived { get; set; }
public string contactID { get; set; }
public string creditAccountID { get; set; }
public string customerTypeID { get; set; }
public string discountID { get; set; }
public string taxCategoryID { get; set; }
public Contact Contact { get; set; }
}
public class Contact
{
public string contactID { get; set; }
public string custom { get; set; }
public string noEmail { get; set; }
public string noPhone { get; set; }
public string noMail { get; set; }
public Addresses Addresses { get; set; }
public Phones Phones { get; set; }
public Emails Emails { get; set; }
public string Websites { get; set; }
public DateTime timeStamp { get; set; }
}
public class Addresses
{
public Contactaddress ContactAddress { get; set; }
}
public class Contactaddress
{
public string address1 { get; set; }
public string address2 { get; set; }
public string city { get; set; }
public string state { get; set; }
public string zip { get; set; }
public string country { get; set; }
public string countryCode { get; set; }
public string stateCode { get; set; }
}
public class Phones
{
public List<Contactphone> ContactPhone { get; set; }
}
public class Contactphone
{
public string number { get; set; }
public string useType { get; set; }
}
public class Emails
{
public List<Contactemail> ContactEmail { get; set; }
}
public class Contactemail
{
public string address { get; set; }
public string useType { get; set; }
}
我看不到我让 LightSpeed 改变他们的 API 所以任何人都可以建议如何让具有 1 个电子邮件地址的客户与我的 class 一起工作吗?
如有任何帮助,我们将不胜感激。
更新:
在提供的帮助下,我已经非常接近一些工作代码了。
这是我的自定义 json 转换器:
public class ContactEmailJsonConverter : JsonConverter<List<ContactEmail>>
{
public override List<ContactEmail> Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options)
{
try
{
if (reader.TokenType == JsonTokenType.StartArray)
{
return (List<ContactEmail>)JsonSerializer
.Deserialize(ref reader, typeToConvert, options);
}
else if (reader.TokenType == JsonTokenType.StartObject)
{
var email = (ContactEmail)JsonSerializer
.Deserialize(ref reader, typeof(ContactEmail), options);
return new List<ContactEmail>(capacity: 1) { email };
}
else
{
throw new InvalidOperationException($"got: {reader.TokenType}");
}
}
catch(Exception ex)
{
return null;
}
}
public override void Write(Utf8JsonWriter writer, List<ContactEmail> value, JsonSerializerOptions options)
{
if ((value is null) || (value.Count == 0))
{
JsonSerializer.Serialize(writer, (ContactEmail)null, options);
}
else if (value.Count == 1)
{
JsonSerializer.Serialize(writer, value[0], options);
}
else
{
JsonSerializer.Serialize(writer, value, options);
}
}
}
但是,我现在找到了一个似乎根本没有电子邮件的联系人。LightSpeed 返回的 JSON 看起来像这样:
"Emails":""
它破坏了我编写的转换器代码。我不确定如何处理这个完全空的对象?
我相信你需要的是转换器。这是一个快速而肮脏的方法,所以我不是 100%,但我相信它应该让你非常接近(而且我没有费心去另一个方向,只是实施 Read
,我想你明白了要点来自这个)。
要使用它,您需要使用转换器标记您的 Emails
class:
public class Emails
{
[JsonConverter(typeof(ContactEmailJsonConverter))]
public Contactemail[] ContactEmail { get; set; }
}
然后像这样写转换器。我在这里所做的基本上是在开头寻找 [
,如果它不存在,则在反序列化之前将其包装。
public class ContactEmailJsonConverter : JsonConverter<Contactemail[]>
{
public override Contactemail[] Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options) =>
{
string content = reader.GetString();
if(!content.Trim().StartsWith("["))
{
content = $"[{content}]";
}
return JsonSerializer.Deserialize<Contactemail[]>(content);
};
public override void Write(
Utf8JsonWriter writer,
Contactemail[] cotactEmails,
JsonSerializerOptions options) =>
throw new NotImplementedException();
}
您或许可以让它更健壮,但这应该让您入门。
注意:我确实将类型更新为 Contactemail[]
,因为我认为 List<T>
在转换器方面有点复杂。下面链接的文档声明使用“工厂模式”并给出了示例,因此如果您想坚持使用 List<T>
,您可以改为遵循它。
您要做的是创建几个自定义 JsonConverter
对象。假设您的模型如下所示:
public class ContactEmail
{
[JsonPropertyName("address")]
public string Address { get; set; }
[JsonPropertyName("useType")]
public string UseType { get; set; }
}
public class Emails
{
public List<ContactEmail> ContactEmail { get; set; }
}
public class Root
{
public Emails Emails { get; set; }
}
首先,您需要设置一个自定义转换器来处理 List<ContactEmail>
以及可能是数组或单个对象的奇怪实例:
public sealed class ContactEmailListJsonConverter
: JsonConverter<List<ContactEmail>>
{
public override List<ContactEmail> Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options)
{
if(reader.TokenType == JsonTokenType.StartArray)
{
return (List<ContactEmail>)JsonSerializer
.Deserialize(ref reader, typeToConvert, options);
}
else if (reader.TokenType == JsonTokenType.StartObject)
{
var email = (ContactEmail)JsonSerializer
.Deserialize(ref reader, typeof(ContactEmail), options);
return new List<ContactEmail>(capacity: 1) { email };
}
else
{
throw new InvalidOperationException($"got: {reader.TokenType}");
}
}
public override void Write(
Utf8JsonWriter writer,
List<ContactEmail> value,
JsonSerializerOptions options)
{
if((value is null) || (value.Count == 0))
{
JsonSerializer.Serialize(writer, (ContactEmail)null, options);
}
else if(value.Count == 1)
{
JsonSerializer.Serialize(writer, value[0], options);
}
else
{
JsonSerializer.Serialize(writer, value, options);
}
}
}
其次,您需要设置一个自定义转换器来处理 Emails
以及它不是实际 Emails
对象的奇怪实例:
public sealed class EmailsJsonConverter : JsonConverter<Emails>
{
public override Emails Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options)
{
// MUST be an object!
if(reader.TokenType == JsonTokenType.StartObject)
{
return (Emails)JsonSerializer
.Deserialize(ref reader, typeToConvert, options);
}
// if it's not an object (ex: string), then just return null
return null;
}
public override void Write(
Utf8JsonWriter writer,
Emails value,
JsonSerializerOptions options)
{
JsonSerializer.Serialize(writer, value, options);
}
}
然后您将转换器添加到您的模型中:
public class Emails
{
[JsonConverter(typeof(ContactEmailListJsonConverter))]
public List<ContactEmail> ContactEmail { get; set; }
}
public class Root
{
[JsonConverter(typeof(EmailsJsonConverter))]
public Emails Emails { get; set; }
}
然后简单地反序列化:
var obj = JsonSerializer.Deserialize<Root>(jsonData);
我正在通过 LightSpeed 呼叫联系人 API。
当我打电话询问客户“A”的详细信息时,JSON 包含他的相关电子邮件的以下内容
{
"Emails": {
"ContactEmail": {
"address": "clienta@yahoo.com",
"useType": "Primary"
}
}
}
当我要求客户“B”的详细信息时,JSON 包含此相关电子邮件的以下内容
{
"Emails": {
"ContactEmail": [{
"address": "clientb1@gmail.com",
"useType": "Primary"
}, {
"address": "clientb2@gmail.com",
"useType": "Secondary"
}
]
}
}
如果我是对的,我相信第一个响应应该是一个数组,即使只返回了 1 个“电子邮件”...?因为系统允许客户在他们的记录中有超过 1 封电子邮件。
这是我要反序列化的 class。它对客户端“B”非常有效,但对客户端“A”无效
public class GetCustomersResponse
{
public Attributes attributes { get; set; }
public List<Customer> Customer { get; set; }
}
public class Attributes
{
public string count { get; set; }
}
public class Customer
{
public string customerID { get; set; }
public string firstName { get; set; }
public string lastName { get; set; }
public string title { get; set; }
public string company { get; set; }
public string companyRegistrationNumber { get; set; }
public string vatNumber { get; set; }
public DateTime createTime { get; set; }
public DateTime timeStamp { get; set; }
public string archived { get; set; }
public string contactID { get; set; }
public string creditAccountID { get; set; }
public string customerTypeID { get; set; }
public string discountID { get; set; }
public string taxCategoryID { get; set; }
public Contact Contact { get; set; }
}
public class Contact
{
public string contactID { get; set; }
public string custom { get; set; }
public string noEmail { get; set; }
public string noPhone { get; set; }
public string noMail { get; set; }
public Addresses Addresses { get; set; }
public Phones Phones { get; set; }
public Emails Emails { get; set; }
public string Websites { get; set; }
public DateTime timeStamp { get; set; }
}
public class Addresses
{
public Contactaddress ContactAddress { get; set; }
}
public class Contactaddress
{
public string address1 { get; set; }
public string address2 { get; set; }
public string city { get; set; }
public string state { get; set; }
public string zip { get; set; }
public string country { get; set; }
public string countryCode { get; set; }
public string stateCode { get; set; }
}
public class Phones
{
public List<Contactphone> ContactPhone { get; set; }
}
public class Contactphone
{
public string number { get; set; }
public string useType { get; set; }
}
public class Emails
{
public List<Contactemail> ContactEmail { get; set; }
}
public class Contactemail
{
public string address { get; set; }
public string useType { get; set; }
}
我看不到我让 LightSpeed 改变他们的 API 所以任何人都可以建议如何让具有 1 个电子邮件地址的客户与我的 class 一起工作吗?
如有任何帮助,我们将不胜感激。
更新:
在提供的帮助下,我已经非常接近一些工作代码了。
这是我的自定义 json 转换器:
public class ContactEmailJsonConverter : JsonConverter<List<ContactEmail>>
{
public override List<ContactEmail> Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options)
{
try
{
if (reader.TokenType == JsonTokenType.StartArray)
{
return (List<ContactEmail>)JsonSerializer
.Deserialize(ref reader, typeToConvert, options);
}
else if (reader.TokenType == JsonTokenType.StartObject)
{
var email = (ContactEmail)JsonSerializer
.Deserialize(ref reader, typeof(ContactEmail), options);
return new List<ContactEmail>(capacity: 1) { email };
}
else
{
throw new InvalidOperationException($"got: {reader.TokenType}");
}
}
catch(Exception ex)
{
return null;
}
}
public override void Write(Utf8JsonWriter writer, List<ContactEmail> value, JsonSerializerOptions options)
{
if ((value is null) || (value.Count == 0))
{
JsonSerializer.Serialize(writer, (ContactEmail)null, options);
}
else if (value.Count == 1)
{
JsonSerializer.Serialize(writer, value[0], options);
}
else
{
JsonSerializer.Serialize(writer, value, options);
}
}
}
但是,我现在找到了一个似乎根本没有电子邮件的联系人。LightSpeed 返回的 JSON 看起来像这样:
"Emails":""
它破坏了我编写的转换器代码。我不确定如何处理这个完全空的对象?
我相信你需要的是转换器。这是一个快速而肮脏的方法,所以我不是 100%,但我相信它应该让你非常接近(而且我没有费心去另一个方向,只是实施 Read
,我想你明白了要点来自这个)。
要使用它,您需要使用转换器标记您的 Emails
class:
public class Emails
{
[JsonConverter(typeof(ContactEmailJsonConverter))]
public Contactemail[] ContactEmail { get; set; }
}
然后像这样写转换器。我在这里所做的基本上是在开头寻找 [
,如果它不存在,则在反序列化之前将其包装。
public class ContactEmailJsonConverter : JsonConverter<Contactemail[]>
{
public override Contactemail[] Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options) =>
{
string content = reader.GetString();
if(!content.Trim().StartsWith("["))
{
content = $"[{content}]";
}
return JsonSerializer.Deserialize<Contactemail[]>(content);
};
public override void Write(
Utf8JsonWriter writer,
Contactemail[] cotactEmails,
JsonSerializerOptions options) =>
throw new NotImplementedException();
}
您或许可以让它更健壮,但这应该让您入门。
注意:我确实将类型更新为 Contactemail[]
,因为我认为 List<T>
在转换器方面有点复杂。下面链接的文档声明使用“工厂模式”并给出了示例,因此如果您想坚持使用 List<T>
,您可以改为遵循它。
您要做的是创建几个自定义 JsonConverter
对象。假设您的模型如下所示:
public class ContactEmail
{
[JsonPropertyName("address")]
public string Address { get; set; }
[JsonPropertyName("useType")]
public string UseType { get; set; }
}
public class Emails
{
public List<ContactEmail> ContactEmail { get; set; }
}
public class Root
{
public Emails Emails { get; set; }
}
首先,您需要设置一个自定义转换器来处理 List<ContactEmail>
以及可能是数组或单个对象的奇怪实例:
public sealed class ContactEmailListJsonConverter
: JsonConverter<List<ContactEmail>>
{
public override List<ContactEmail> Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options)
{
if(reader.TokenType == JsonTokenType.StartArray)
{
return (List<ContactEmail>)JsonSerializer
.Deserialize(ref reader, typeToConvert, options);
}
else if (reader.TokenType == JsonTokenType.StartObject)
{
var email = (ContactEmail)JsonSerializer
.Deserialize(ref reader, typeof(ContactEmail), options);
return new List<ContactEmail>(capacity: 1) { email };
}
else
{
throw new InvalidOperationException($"got: {reader.TokenType}");
}
}
public override void Write(
Utf8JsonWriter writer,
List<ContactEmail> value,
JsonSerializerOptions options)
{
if((value is null) || (value.Count == 0))
{
JsonSerializer.Serialize(writer, (ContactEmail)null, options);
}
else if(value.Count == 1)
{
JsonSerializer.Serialize(writer, value[0], options);
}
else
{
JsonSerializer.Serialize(writer, value, options);
}
}
}
其次,您需要设置一个自定义转换器来处理 Emails
以及它不是实际 Emails
对象的奇怪实例:
public sealed class EmailsJsonConverter : JsonConverter<Emails>
{
public override Emails Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options)
{
// MUST be an object!
if(reader.TokenType == JsonTokenType.StartObject)
{
return (Emails)JsonSerializer
.Deserialize(ref reader, typeToConvert, options);
}
// if it's not an object (ex: string), then just return null
return null;
}
public override void Write(
Utf8JsonWriter writer,
Emails value,
JsonSerializerOptions options)
{
JsonSerializer.Serialize(writer, value, options);
}
}
然后您将转换器添加到您的模型中:
public class Emails
{
[JsonConverter(typeof(ContactEmailListJsonConverter))]
public List<ContactEmail> ContactEmail { get; set; }
}
public class Root
{
[JsonConverter(typeof(EmailsJsonConverter))]
public Emails Emails { get; set; }
}
然后简单地反序列化:
var obj = JsonSerializer.Deserialize<Root>(jsonData);