2017-01-13 10 views
0

だから、私のDocumentDBに私は、次の書類を持っていることがあります。ここにAzureのサービス・ファブリックとDocumentDBメッセージのシリアル化の問題

public class acontent 
    { 
     public int x { get; set; } 
     public int y { get; set; } 
    } 

    public class document 
    { 
     public int id { get; set; } 
     public string type { get; set; } 
     public object content { get; set; } 
    } 

    public class documenta : document 
    { 
     public new acontent content { get; set; } 
    } 

アイデア:このモデルによってバックアップすることができる

{ 
    "id": 1, 
    "type": "A", 
    "content": { 
    "x": 1, 
    "y": 2 
    } 
} 

その文書は種類によって内容が異なる複雑なオブジェクトです。今

、 - 私のServiceFabricアプリケーションでは、私はDocumentDBから読み込み、ServiceProxyから呼び出されたときに文書型オブジェクトを返す必要がありますステートレスmicroserviceを持っています。

DocumentDB SDKのDocumentQueryはデータベース照会時にJson.NETシリアライザを使用し、servicefabricはサービスメッセージのシリアル化にDataContractSerializerを使用しています。

Newtonsoft.Json.Linq.JObject 

しかし、それはあなたが例外を取得返さサービスメッセージを通じてバックシリアライズされています:

だから、 内容一部文書クラスは、それがなっDocumentDBから直列化復元されている

タイプ 'Newtonsoft.Json.Linq.JToken'は、再帰的なコレクションデータ 契約であり、サポートされていません。 コレクション 'Newtonsoft.Json.Linq.JToken'の定義を変更して、 への参照を削除することを検討してください。

using System; 
using System.IO; 
using System.Text; 
using System.Runtime.Serialization.Json; 
using Newtonsoft.Json; 

namespace jsoinissue 
{ 
    public class acontent 
    { 
     public int x { get; set; } 
     public int y { get; set; } 
    } 

    public class document 
    { 
     public int id { get; set; } 
     public string type { get; set; } 
     public object content { get; set; } 
    } 

    public class documenta : document 
    { 
     public new acontent content { get; set; } 
    } 

    public class Program 
    { 
     private const string JSON_A = "{\"id\":1,\"type\":\"A\",\"content\":{\"x\":1,\"y\":2}}"; 

     private static string SerializeObject<T> (T obj) 
     { 
      try 
      { 
       DataContractJsonSerializer js = new DataContractJsonSerializer(typeof(T)); 
       using (var ms = new MemoryStream()) 
       { 
        js.WriteObject(ms, obj); 
        ms.Position = 0; 
        using (var sr = new StreamReader(ms)) 
         return sr.ReadToEnd(); 
       } 
      } 
      catch (Exception e) 
      { 
       return String.Format("EXCEPTION: {0}",e.Message); 
      } 
     } 

     public static void Main() 
     { 
      var A = JsonConvert.DeserializeObject<document>(JSON_A); 
      var a = SerializeObject<document>(A);//HERE BE TROUBLE 
      Console.WriteLine(a); 
      Console.ReadKey(); 
     } 
    } 
} 

どのように私は最高のこの問題を解決することができます:

は、この問題はfolowingコードを試す説明するために?

+0

'DataContractJsonSerializer'では、フリーフォームのJSONデータのデシリアライズとシリアライズをサポートしていません。ちょうど' DataContractSerializer'がフリーフォームXMLデータをサポートしていないのと同じです。あなたのデータモデルを静的に完全に何かに変更することをお勧めします。それは可能ですか? – dbc

+0

dbc、このような複雑な型を扱うことができるソリューションを構築したいと思っていました。マイクロサービスはidと型を照会するだけで、サービスの呼び出し側が下流でさらにシリアライズを実行する必要があります。 – ifxdev

+0

コンテンツは常に単純なJSONオブジェクトですか、複数のオブジェクトまたは配列のネストされたレベルを持つことができますか?私。 'Dictionary 'で十分でしょうか? – dbc

答えて

0

代わりにDataContractSerializerからシリアライザへの切り替えを検討しましたか? Here's別のシリアライザをどのように接続しますか?

class InitializationCallbackAdapter 
{ 
    public Task OnInitialize() 
    { 
     this.StateManager.TryAddStateSerializer(new MyStateSerializer()); 
     return Task.FromResult(true); 
    } 

    public IReliableStateManager StateManager { get; set; } 
} 

class MyStatefulService : StatefulService 
{ 
    public MyStatefulService(StatefulServiceContext context) 
     : this(context, new InitializationCallbackAdapter()) 
    { 
    } 

    public MyStatefulService(StatefulServiceContext context, InitializationCallbackAdapter adapter) 
     : base(context, new ReliableStateManager(context, new ReliableStateManagerConfiguration(onInitializeStateSerializersEvent: adapter.OnInitialize))) 
    { 
     adapter.StateManager = this.StateManager; 
    } 
} 

これはnewtonsoftなどです。また、私はこのメソッドが現在 "廃止予定"とマークされているとは思っていますが、代替手段はありませんので、あなたの問題を解決すればそれを使用してください。

+0

あなたの答えをありがとう、私はそれを感謝します。今は、 'NewStartSerializer'クラスを設計して、Newtonsoftをシリアライゼーションに使う方法に苦しんでいます。何かアドバイス? – ifxdev

1

基本的な問題は、DataContractJsonSerializerは、型指定されていない自由形式のJSONデータをサポートしていないことです。 Working with untyped JSON in a WCF serviceで説明したように、この目的でSilverlightにSystem.Jsonという名前空間が追加されましたが、完全な.NETクラスライブラリにはなりませんでした。

代わりに、ステートレスマイクロサービスでネストされたシリアル化を実行できます。フリーフォームJSONは、データコントラクトシリアライザを使用してシリアル化するときにエスケープされた文字列リテラルとして表されます。したがって、あなたのクラスは、このようなものになります。そして、受信システム上で、あなたはデータコントラクトを使用してdocumentにデシリアライズすることができます

{ 
    "content":"{\"x\":1,\"y\":2}", 
    "id":1, 
    "type":"A" 
} 

[DataContract] 
[JsonObject] 
public abstract class documentbase 
{ 
    [DataMember] 
    [JsonProperty] 
    public int id { get; set; } 

    [DataMember] 
    [JsonProperty] 
    public string type { get; set; } 

    [IgnoreDataMember] 
    [JsonProperty("content")] 
    public abstract JToken JsonContent { get; set; } 

    [JsonIgnore] 
    [DataMember(Name = "content")] 
    string DataContractContent 
    { 
     get 
     { 
      if (JsonContent == null) 
       return null; 
      return JsonContent.ToString(Newtonsoft.Json.Formatting.None); 
     } 
     set 
     { 
      if (string.IsNullOrEmpty(value)) 
       JsonContent = null; 
      else 
       JsonContent = JToken.Parse(value); 
     } 
    } 
} 

[DataContract] 
[JsonObject] 
public class document : documentbase 
{ 
    JToken content; 

    public override JToken JsonContent { get { return content; } set { content = value; } } 
} 

[DataContract] 
[JsonObject] 
public class document<T> : documentbase where T : class 
{ 
    [IgnoreDataMember] 
    [JsonIgnore] 
    public T Content { get; set; } 

    public override JToken JsonContent 
    { 
     get 
     { 
      if (Content == null) 
       return null; 
      return JToken.FromObject(Content); 
     } 
     set 
     { 
      if (value == null || value.Type == JTokenType.Null) 
       Content = null; 
      else 
       Content = value.ToObject<T>(); 
     } 
    } 
} 

を次にSerializeObject<document>(A)によって生成されたJSONは次のようになりますデシリアライズされたJToken JsonContentLINQ to JSONをクエリします。あるいは、受信システムがdocument<acontent>を予期することを知っている場合、documentdocument<T>は同じデータ契約を持っているため、データ契約JSONを逆シリアル化できます。