2016-03-23 10 views
1

私はこの問題を数時間解決しようとしています。私は多くのアプローチを試み、多くの記事を読んでいます。私は解決策を見つけることができないようです。Json.Net複雑なオブジェクトの非直列化 - 基本クラスをプロパティとして含む基本クラス

私は別の派生型を含む型を派生させたオブジェクト階層を持っています。私はJson.NetのTypeNameHandling設定を使用しています。私はAutoにシリアライズとデシリアライズの両方を設定しました。

得JSONは:

"[\r\n {\r\n \"$type\": \"Common.Monitors.HeartbeatMonitor, Common\",\r\n \"ClassName\": \"HeartbeatMonitor\",\r\n \"ServerGroupMonitorId\": 1,\r\n \"Instructions\": {\r\n  \"$type\": \"Common.Monitors.HeartbeatMonitorInstructions, Common\",\r\n  \"RunIntervalInMinutes\": 1\r\n },\r\n \"LastExecutionDateTime\": \"2016-03-22T16:35:18.7458519\"\r\n },\r\n {\r\n \"$type\": \"Common.Monitors.DiskSpaceMonitor, Common\",\r\n \"ClassName\": \"DiskSpaceMonitor\",\r\n \"ServerGroupMonitorId\": 2,\r\n \"Instructions\": {\r\n  \"$type\": \"Common.Monitors.DiskSpaceMonitorInstructions, Common\",\r\n  \"DriveLetter\": \"C:\\\",\r\n  \"AlertWhenPercentFreeLessThan\": 20,\r\n  \"RunIntervalInMinutes\": 30\r\n },\r\n \"LastExecutionDateTime\": \"2016-03-22T16:15:18.7458519\"\r\n }\r\n]" 

次の使用デシリアライズしよう:Newtonsoft」タイプの

例外:

string json = response.Content.ReadAsStringAsync().Result; 

IEnumerable<MonitorBase> monitors = JsonConvert.DeserializeObject<IEnumerable<MonitorBase>>(json, new JsonSerializerSettings 
      { 
       TypeNameHandling = TypeNameHandling.Auto 
      }); 

私は次の例外を受け取ります。 Json.JsonSerializationException 'はNewtonsoft.Json.dllで発生しましたが、ユーザーコードでは処理されませんでした。

追加情報:エラー変換値

"[ 
    { 
    "$type": "Common.Monitors.HeartbeatMonitor, Common", 
    "ClassName": "HeartbeatMonitor", 
    "ServerGroupMonitorId": 1, 
    "Instructions": { 
     "$type": "Common.Monitors.HeartbeatMonitorInstructions, Common", 
     "RunIntervalInMinutes": 1 
    }, 
    "LastExecutionDateTime": "2016-03-22T16:35:18.7458519" 
    }, 
    { 
    "$type": "Common.Monitors.DiskSpaceMonitor, Common", 
    "ClassName": "DiskSpaceMonitor", 
    "ServerGroupMonitorId": 2, 
    "Instructions": { 
     "$type": "Common.Monitors.DiskSpaceMonitorInstructions, Common", 
     "DriveLetter": "C:\\", 
     "AlertWhenPercentFreeLessThan": 20, 
     "RunIntervalInMinutes": 30 
    }, 
    "LastExecutionDateTime": "2016-03-22T16:15:18.7458519" 
    } 
]" 

'System.Collections.Generic.IEnumerable`1 [Common.Monitors.MonitorBase]' と入力します。 パス '、行1、位置943

HeartbeatMonitorDiskSpaceMonitorタイプはMonitorBaseから派生し、それぞれInstructionsタイプがMonitorInstructionBase由来します。

私はこれがむしろ一般的なシナリオではないとは想像できないので、私は何か明白でないことを仮定していません。

答えて

3

エスケープされた引用符\"、目に見える改行\r\nとJSON全体が引用されていることからも分かるように、JSONは二重シリアル化されている可能性があります。二重シリアル化されたJSONを逆シリアル化すると、結果はオブジェクトではなく文字列になります。これは明らかにどの種類のIEnumerable<T>にも変換できません。したがって、エラー。

JSONのソースを制御する場合は、オブジェクトを1回だけシリアライズしてください。この問題の一般的な原因は、Web APIなどの一部のフレームワークが自動的にシリアライズを行うことを認識していないため、オブジェクトを手動で最初にシリアル化して戻す前に、JSONを二重シリアル化することになります。

JSONのソースを制御していない場合や、所有者に解決させることができない場合は、JSONを2回デシリアライズしてクライアント側で修正することができます。 JSON文字列、次に2番目の文字列からオブジェクトを生成します。例えば:私は手動でJson.NetのTypeNameHandling設定を利用するためには、あなたのオブジェクトをシリアル化している、とあなたがへの道を探していることをあなたのコメントから見る

string escapedJson = response.Content.ReadAsStringAsync().Result; 

string realJson = JsonConvert.DeserializeObject<string>(escapedJson); 

IEnumerable<MonitorBase> monitors = 
    JsonConvert.DeserializeObject<IEnumerable<MonitorBase>>(realJson, 
     new JsonSerializerSettings 
     { 
      TypeNameHandling = TypeNameHandling.Auto 
     }); 

EDIT

二重シリアル化を避けてください。

あなたは基本的に2つのオプションがあります。

  1. がWeb APIのグローバルシリアライズ設定にTypeNameHandling設定を追加して、あなたの方法から手動シリアル化コードを削除します。これを行うには、global.asaxApplication_Start()メソッドに次を追加します。

    var settings = GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings; 
    settings.TypeNameHandling = TypeNameHandling.Auto; 
    
  2. また、あなたはJSONを含むStringContent対象とし、application/jsonからmediaTypeセットでHttpResponseMessageを作成して返すようにWeb API方法を変更することができます。これにより、Web APIが結果を再直列化しようとしないようにする必要があります。

    string json = JsonConvert.SerializeObject(monitors, new JsonSerializerSettings 
    { 
        TypeNameHandling = TypeNameHandling.Auto, 
        Formatting = Formatting.Indented 
    }); 
    HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK); 
    response.Content = new StringContent(json, Encoding.UTF8, "application/json"); 
    return response; 
    
+0

おかげブライアン。私はプロセスの両面を制御し、Web APIを使用しています。しかし、私は手動でデータをシリアル化しているわけではないので、なぜ二重シリアル化が発生しているのか理解している必要があります。 – chad

+0

さて、この問題は、シリアル化されたjsonに$ type情報を取得するためにJson.NetのTypeNameHandling設定を使用する必要があるという事実に関連していると思います。したがって、TypeNameHandling設定でJsonConvert.SerializeObjectを実行していて、その文字列を返します。 Web APIはjsonをもう一度シリアル化しているようです。それを防ぐ方法はありますか?私は明らかなことは何も見つけていない。 – chad

+0

私はこの問題を解決するのに役立ついくつかの情報で私の答えを更新しました。 –

関連する問題