首页 > 解决方案 > 修复返回的 JSON 中的数组

问题描述

我正在从 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 封电子邮件。

这是我要反序列化的类。它适用于客户端“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 个电子邮件地址的客户与我的班级一起工作?

任何帮助将不胜感激。

更新:

在给定的帮助下,我已经非常接近一些工作代码。

这就是我为自定义 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":""

它破坏了我编写的转换器代码。我不确定如何处理这个完全空的对象?

标签: c#jsonlightspeed

解决方案


我相信你需要的是一个转换器。这是一个快速和肮脏的,所以我不是 100%,但我相信它应该让你非常接近(我没有费心去另一个方向,只是实施Read,我想你从中得到了要点)。

要使用它,您可以使用Emails转换器标记您的课程:

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>可以改为遵循。

更多文档:https ://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-converters-how-to?pivots=dotnet-5-0


推荐阅读