簡體   English   中英

修復 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 個 email。

這是我試圖反序列化的 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 email 地址的客戶端與我的 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);
        }
    }
}

但是,我現在發現一個聯系人似乎根本沒有 email .. LightSpeed 返回的 JSON 看起來像這樣:

 "Emails":""

它破壞了我編寫的轉換器代碼。 我不確定如何處理這個完全空的 object?

我相信你需要的是一個轉換器。 這是一個快速和骯臟的,所以我不是 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> ,您可以遵循它。

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

您將要做的是創建幾個自定義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>以及它可能是一個數組或單個 object 的奇怪實例:

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的奇怪實例 object:

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);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM