2016-12-07 72 views
2

我正在使用繼承代碼,與本質上是第三方設備進行通信。我的開發套件是VS 2015,使用C#和NewtonSoft.Json庫。如何處理從JsonConvert.DeserializeObject返回的Json錯誤代碼<T>()

我的「頂級」程序看起來有點像這樣(的一些細節省略清晰):

public JsonResponse<T> SendTypedApiRequest<T>(JsonCommand command, 
    string apiPath, string description, int expectedResponseCode = 0) 
{ 
    try 
    { 
     var r = SendPost(apiPath, command); 
     if (r.Code == OK && r.Response != null) { 
      var jsonResponse = JsonResponse<T>.Deserialize(r.Response); 

      if (jsonResponse.RetCode != expectedResponseCode) { 
       // handle errors 
      } 
     } 
    } 
    catch(){}; 
} 

在另一個文件中我有以下幾點:

public static JsonResponse<T> Deserialize(string json, 
     JsonSerializerSettings settings = null) 
    { 
     return JsonConvert.DeserializeObject<JsonResponse<T>>(json, settings); 
    } 

我預計從返回這個帖子的設備是數字值,所以在這種情況下T是'int'(或者說是int的JsonResponse):

{"retCode":0,"retMsg":"OK","data":41272} 

但是,當適當的條件沒有滿足,我得到這個:

{"retCode":1000,"retMsg":"No admin","data":{}} 

似乎不夠公平嗎?但是,由於這是一個類型化的響應反序列化器,它會在{}上扼殺,希望得到一個整數而不是大括號。我得到的是一個JsonReaderException「解析值時遇到意外的字符:{。」我想得到的是來自Json響應的retCode和retMsg,所以我可以將實際的錯誤條件傳回給用戶。 JsonReaderException根本沒有幫助。

我嘗試使用JsonSerializerSettings的空值和空值,但它們在這種情況下不起作用。我似乎無法找到處理這種情況的標準方法。我可以在最後調用JsonConvert.DeserializeObject()的時候放一個try/catch來從響應中提取實際的錯誤並將它追回堆棧,但這看起來很粗糙和笨拙 - 沒有邏輯來處理直到我在代碼中達到3或4個級別(所有事情都期待輸入響應)。

有沒有一種優雅的方式來處理這個問題?有沒有一個規範的方法來處理這個問題?看來,我提出的每種方法都是笨拙和醜陋的,或根本不起作用。

TIA,戴夫

+0

什麼是JsonResponse? – DavidG

+0

我想你可以在這裏做兩件事。在您的模型中,將'data'更改爲可爲null的int。然後確保在啓用了忽略空值設置的情況下反序列化JSON。 – silkfire

+0

JsonResponse如果是一個本地類 - 我錯過了,因爲我對Json相當陌生,而且這段代碼有很多的問題。如果有必要,我可以在這裏發佈該班的裸骨頭作爲編輯... – DaveN59

回答

2

一種可能的方法是創建一個自定義JsonConverterJsonResponse<T>處理類型的差異。這個想法是將JSON數據加載到中間JObject中,然後在單獨的步驟中處理「行爲良好」的屬性(例如RetCode, RetMsg)和可能不正確的Data屬性。這樣,如果Data屬性的轉換失敗,您仍然可以恢復其餘的響應。

這裏的轉換可能是什麼樣子:

public class JsonResponseConverter : JsonConverter 
{ 
    public override bool CanConvert(Type objectType) 
    { 
     return objectType.IsGenericType && 
       objectType.GetGenericTypeDefinition() == typeof(JsonResponse<>); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     // Load JSON data into a JObject 
     JObject obj = JObject.Load(reader); 

     // Remove the problematic data property from the JObject 
     JProperty dataProp = obj.Property("data"); 
     if (dataProp != null) dataProp.Remove(); 

     // Create a JsonResponse object and populate it with the 
     // well-behaved properties in the JObject (e.g. RetCode, RetMsg) 
     object jsonResponse = Activator.CreateInstance(objectType); 
     serializer.Populate(obj.CreateReader(), jsonResponse); 

     try 
     { 
      // Now try to add the data property into the same response 
      if (dataProp != null) 
      { 
       JObject data = new JObject(dataProp); 
       serializer.Populate(data.CreateReader(), jsonResponse); 
      } 
     } 
     catch (JsonException) { } // if it doesn't work, eat the exception 

     return jsonResponse; 
    } 

    public override bool CanWrite 
    { 
     get { return false; } 
    } 

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

要使用轉換器,你可以在你SendTypedApiRequest<T>方法將它添加到JsonSerializerSettings並通過設置您的JsonResponse<T>.Deserialize方法。

var r = SendPost(apiPath, command); 
    if (r.Code == OK && r.Response != null) 
    { 
     var settings = new JsonSerializerSettings(); 
     settings.Converters.Add(new JsonResponseConverter()); 

     var jsonResponse = JsonResponse<T>.Deserialize(r.Response, settings); 
     ... 
    } 

這裏是一個演示:https://dotnetfiddle.net/oWYkoU

+0

太棒了!這就是我一直在尋找的。儘管我有1條評論和1條問題。評論:CanWrite()方法是多餘的,可以消除 - 不是什麼大事,ReSharper標記它。問題:我得到一個Missing Method異常,在DotNetFiddle的示例117行中尋找目標「對象」的默認構造函數。在這種情況下,這將是JsonResponse ,但它可以是任何東西。我堅持使用.NET 4,因爲我們的一些客戶仍然使用XP(是的,我知道,但他們在中國......) - 這可能是4而不是4.5的問題嗎? – DaveN59

+0

關於'CanWrite',這對我來說簡直就是假 - 它應該返回false,而不是調用基類。我已經在答案和小提琴中糾正了它。我忽略了CanWrite,因爲WriteJson沒有實現,默認情況下基本實現返回true。如果你只反序列化並且從不序列化JsonResponse(可能是這種情況),那麼它並不重要。 –

+0

如果您的JsonResponse類缺少默認構造函數(即沒有參數的函數),則會發生缺少的方法異常。你沒有顯示你的類定義,所以我認爲它有一個默認的構造函數。您需要修改JsonResponse類以提供默認構造函數,否則您需要修改Activator.CreateInstance()調用來傳遞適當的構造函數參數以創建JsonResponse對象。如果你無法正常工作,請使用JsonResponse類def編輯你的問題,我會嘗試更新我的答案以解決問題。 –

0

你可以欺騙和更改數據int類型dynamic。有點破解,但它可能會解決你的問題。