Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# Azure服务结构和DocumentDB消息序列化问题_C#_Json_Serialization_Azure Service Fabric_Azure Cosmosdb - Fatal编程技术网

C# Azure服务结构和DocumentDB消息序列化问题

C# Azure服务结构和DocumentDB消息序列化问题,c#,json,serialization,azure-service-fabric,azure-cosmosdb,C#,Json,Serialization,Azure Service Fabric,Azure Cosmosdb,因此,-在我的文档数据库中,我可能有以下文档: { "id": 1, "type": "A", "content": { "x": 1, "y": 2 } } 该模型可能支持以下内容: public class acontent { public int x { get; set; } public int y { get; set; } } public class document {

因此,-在我的文档数据库中,我可能有以下文档:

{
  "id": 1,
  "type": "A",
  "content": {
    "x": 1,
    "y": 2
  }
}
该模型可能支持以下内容:

   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; }
    }
这里的想法是,文档是一个复杂的对象,其内容可能因类型而异

现在,-在我的ServiceFabric应用程序中,我有一个无状态的微服务,它从DocumentDB读取数据,当从ServiceProxy调用时,应该返回一个文档类型的对象

其中的问题是来自DocumentDB SDK的DocumentQuery在查询数据库时使用Json.NET序列化程序,而servicefabric使用DataContractSerializer序列化服务消息

因此,当document类的内容部分从DocumentDB反序列化时,它将变成:

Newtonsoft.Json.Linq.JObject
但是,当通过返回的服务消息将其序列化回时,会出现异常:

类型“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();
        }
    }
}
使用系统;
使用System.IO;
使用系统文本;
使用System.Runtime.Serialization.Json;
使用Newtonsoft.Json;
名称空间问题
{
公共类内容
{
公共整数x{get;set;}
公共整数y{get;set;}
}
公共类文档
{
公共int id{get;set;}
公共字符串类型{get;set;}
公共对象内容{get;set;}
}
公共类文档:文档
{
公共新内容{get;set;}
}
公共课程
{
私有常量字符串JSON_A=“{\'id\':1,\'type\':\'A\',\'content\':{\'x\':1,\'y\':2}}”;
私有静态字符串序列化对象(T obj)
{
尝试
{
DataContractJsonSerializer js=新的DataContractJsonSerializer(typeof(T));
使用(var ms=new MemoryStream())
{
js.WriteObject(ms,obj);
ms.Position=0;
使用(var sr=新的StreamReader(ms))
返回sr.ReadToEnd();
}
}
捕获(例外e)
{
返回String.Format(“异常:{0}”,e.Message);
}
}
公共静态void Main()
{
var A=JsonConvert.DeserializeObject(JSON_A);
var a=SerializeObject(a);//这里有麻烦了
控制台写入线(a);
Console.ReadKey();
}
}
}

如何才能最好地解决此问题?

您的基本问题是
DataContractJsonSerializer
不支持非类型化、自由格式的JSON数据。正如前面所解释的,名称空间是为此目的添加到Silverlight的,但它似乎从未进入完整的.Net类库

相反,在无状态微服务中,当使用数据协定序列化程序进行序列化时,可以执行嵌套序列化,其中自由格式JSON表示为转义字符串文本。因此,您的类将如下所示:

[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>();
        }
    }
}

然后,在接收系统上,您可以使用数据协定序列化程序反序列化为
文档
,然后使用查询反序列化的
JToken JsonContent
。或者,如果接收系统知道需要一个
文档
,它可以反序列化数据契约JSON,因为
文档
文档
具有相同的数据契约。

您是否考虑过将DataContractSerializer改为支持更好的序列化器?如何插入不同的序列化程序

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或其他什么。此外,我认为该方法目前标记为“不推荐”,但是没有其他选择,因此如果它解决了您的问题,请继续使用它

DataContractJsonSerializer
实际上不支持反序列化和序列化自由格式的JSON数据,就像
DataContractSerializer
不支持自由格式的XML数据一样。我建议将您的数据模型更改为完全静态类型。这可能吗?dbc,-嗯,我有点希望构建一个能够处理如此复杂类型的解决方案。微服务应该只查询id和类型,服务的调用者应该在下游执行进一步的序列化。内容总是一个简单的JSON对象,还是可以有多个嵌套级别的对象或数组?例如,
字典
是否足够?它也可以是多个嵌套级别的对象。我看不出字典在这里是如何工作的,请解释一下?如果你有多个层次的话就不会了。它只适用于你问题中所示的单一级别,因此我要求澄清。谢谢你的回答,我对此表示感谢。现在,我正在努力研究如何设计
mystatesializer
类来使用Newtonsoft进行序列化。有什么建议吗?
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;
    }
}