2017-07-17 47 views
0

我正在與各種端點上的API進行通信。所有響應在meta中都有一些共享字段,然後是一個可包含任意數量自定義對象的data對象。CustomJsonConverter將一個字段反序列化爲JSON,其中一個字段可能是多個自定義對象

的幾個例子: 1)一種有效載荷返回data含有accounts[]

{ 
"meta": { 
    "timestamp": "2017-07-14T12:59:34-04:00", 
    "code": 200 
}, 
"data": { 
    "accounts": [ 
     { 
      "address": "Main Street", 
      "country": "US", 
      "email": "[email protected]", 
      "city": "MyTown", 
      "accountName": "MyAccount", 
      "account": 123456, 
      "contact": "" 
     } 
    ] 
} 
} 

2)有效載荷返回data含有shipments[]

{ 
"meta": { 
    "timestamp": "2017-07-14T13:46:42-04:00", 
    "code": 400 
}, 
"data": { 
    "shipments": [ 
     { 
      "distributionCenter": "123", 
      "packages": [ 
       { 
        "packageDetails": {}, 
        "consigneeAddress": {}, 
        "errors": [ 
         { 
          "errorCode": "VALIDATION_ERROR", 
          "errorId": 0, 
          "errorMessage": "INVALID_LOGIN" 
         } 
        ], 
      ], 
      "status": { 
       "timestamp": "2017-07-14T13:46:42-0400", 
       "numAccepted": 0, 
       "numRejected": 1, 
       "code": "ERROR" 
      }, 
     } 
    ] 
} 
} 

我需要有訪問shipments[]當我打shipments端點,與accounts[]相同時點擊accounts端點。所以data.accounts[0].email是可以訪問的。

這樣做的破解方式似乎創建了一個具有所有可能的對象類型的類,所以當序列化/反序列化發生時,那些不存在的就是空。

public class ApiResponse 
{ 
    public Meta meta { get; set; } 
    public Data data { get; set; } 
} 

public class Meta 
{ 
    public string code { get; set; } 
    public DateTime timestamp { get; set; } 
} 

public class Data 
{ 
    public Account[] accounts { get; set; } 
    public Shipment[] shipments { get; set; } 
} 

但我想知道是否有辦法用Newtonsoft JSON自定義JsonConverter做到這一點。薩Data類的樣子:

[JsonConverter(typeof(DataConverter))] 
public class Data 
{ 
    \\not sure what to put here... 
} 

如何讓ReadJson認識到自定義對象的任何輸入?或者在其他json.net的方式來完成這個?

class DataConverter : JsonConverter 
{ 
    public override bool CanConvert(Type objectType) 
    { 
     return (objectType == typeof(Data)); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     if (reader.Value.GetType() == Shipment) 
     /// this throws error "not valid type in this context" 


     throw new NotImplementedException(); 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     throw new NotImplementedException(); 
    } 
} 
} 
+0

*我想知道是否有一種方法可以使用自定義的JsonConverter * - 你想讓你的'Data'類型看起來像什麼?你在哪裏應用轉換器? – dbc

+0

對「數據」的外觀沒有什麼看法 - 只會更喜歡不必'{get; set;}'爲每個可能的對象類型(只給出了兩個例子,但我正在處理6+對象類型''數據'可以包含)。添加了我在上面應用轉換器的示例 – dbJones

+0

當您碰到相應的端點時,API是否具有有關它在數據中返回的對象類型的文檔?它必須公開這些信息。 – niksofteng

回答

3

我會重塑類來服務不同的data類型。首先,我只想有一個通用的ApiResponse<T>如下:

public class ApiResponse<T> where T : class { 
    public Meta Meta { get; set; } 
    public T Data { get; set; } 
} 

public class AccountData { 
    public Account[] Accounts { get; set; } 
} 

public class ShipmentData { 
    public Shipment[] Shipments { get; set; } 
} 

不要有什麼數據看起來像

視覺當你打你知道一個特定的終點什麼API將返回。如果您要求提供帳戶,它不會爲您提供貨件或其他物品,反之亦然。如果可用,請檢查API文檔。

而且你可以簡單地創建一個通用的API請求方法,使用這種方法,要求不同種類的數據即,AccountData,ShipmentData等

ApiResponse<T> MakeApiRequest<T>(string apiUrl) where T : class { 
    // Call API the way you want and get JSON response 
    var jsonResponse = "{ \"data\": { \"accounts\": [ { \"address\": \"Main Street\" } ] } }"; // Example data hard-coded 
    // Desrialize JSON response into ApiResponse<T> 
    var apiResponse = JsonConvert.DeserializeObject(jsonResponse, typeof(ApiResponse<T>)) as ApiResponse<T>; 
    return apiResponse; 
} 

和呼叫端點:

var accountApiResponse = MakeApiRequest<AccountData>("<accounts_api_url>"); 
var shipmentApiResponse = MakeApiRequest<ShipmentData>("<shipments_api_url>"); 
+0

通用api請求方法的獎勵分數。在我的思想中沒有得到那麼多。謝謝! – dbJones

0

如果你把你的數據類只是對象

public class Data 
{ 
    public object[] ResponsePayload {get;set;} 
} 
+0

使用json.net進行反序列化時,這會導致問題,因爲上面的屬性名稱('ResponsePayload')與json中的任何字段名稱不匹配。 Usin'[JsonProperty(「shipments」)]'作爲映射工作之一,但是每個字段只能放置一個'JsonProperty'。我正在處理6個以上的對象,每個對象都有自己的名字,所以這種方法在這種情況下不起作用 – dbJones

+0

你的JSON響應在其中不會有「Shipment」或「Account」字段,但所有這些對象都可以存儲在一個對象數組中。但是你說你需要使用指向數據的json響應關鍵字,這取決於數據類型嗎? – victor

0

的陣列可以直接從您的HttpClient做到這一點:

var myResponsePayload = await response.Content.ReadAsAsync<MyTypeHere>().ConfigureAwait(false); 

當你打你的API,他們」我會以這種格式進來。只要確保你想在你的類中設置的屬性與JSON中的內容對齊即可。

如果您沒有訪問Web服務,而是從文件或數據庫中讀取數據,我建議使用Newtonsoft Json,這是一種廣泛使用的用於json反序列化的NuGet包。

你可能最終得到這樣的:

var results = _serializer.Deserialize<IEnumerable<MyBingyMathob>>(reader); 

這將工作,只要你序列與公衆制定者有公開訪問的屬性的類。如果你不想要所有的數據,那麼丟失的字段將被丟棄。

+0

上面概述的自定義轉換器是Json.Net(又名Newtonsoft Json)的內置部分。所以試圖走這條路。 – dbJones

1

您需要任何特定的數據移動到子類是這樣的:

public class AccountData 
{ 
    public Account[] accounts { get; set; } 
} 

public class ShipmentData 
{ 
    public Shipment[] shipments { get; set; } 
} 

從那裏您將可以使用一個響應等級去一個抽象的是與普通數據和兩個具體的類與特定的根類似的信息如下:

public abstract class ApiResponse 
{ 
    public Meta meta { get; set; } 
} 

public class AccountApiResponse : ApiResponse 
{ 
    public AccountData data { get; set; } 
} 

public class ShipmentApiResponse : ApiResponse 
{ 
    public ShipmentData data { get; set; } 
} 

從那裏當你的帳戶終結點呼叫時,可以與檢索數據:

var accountResponse = JsonConvert.DeserializeObject<AccountApiResponse>(json); 

而且出貨量:

var shipmentResponse = JsonConvert.DeserializeObject<ShipmentApiResponse>(json); 

希望它能幫助。

相關問題