Service Fabric可靠集合:序列化问题

本文关键字:序列化 问题 集合 Fabric Service | 更新日期: 2023-09-27 18:26:09

可靠集合(队列)值存储一些复杂类型的SomeUnit

我已经将其标记为[DataContract],将其成员标记为[DataMember],并在其上添加了[KnownType(typeof(SomeUnit))]属性。

看起来现在SomeUnit正在序列化,但随后引发了反序列化异常:

元素"urn:ServiceFabric.Communication:item"包含来自映射到名称的类型'http://schemas.datacontract.org/2004/07/RP.Core:SomeUnit"。这个反序列化程序不知道映射到此名称的任何类型。如果您正在使用DataContractResolverDataContractSerializer或将"SomeUnit"对应的类型添加到已知类型的列表-例如,使用KnownTypeAttribute属性,或者将其添加到传递给串行器。

我该如何解决?

Service Fabric可靠集合:序列化问题

由于您没有显示任何代码,我们只能猜测是什么导致了这种情况。

如果使用具有通用项类型的可靠队列,例如SomeUnit基类,则会出现此问题。

// Using reliable collection with a base item type
IReliableQueue<BaseClass> myQueue = ...;
// Store derived item in the queue
SomeUnit myData = ...; // SomeUnit inherit from BaseClass
await myQueue.EnqueueAsync(txn, myData); // OK to store but won't deserialize!

该队列的反序列化程序知道如何解析BaseClass,但它不会隐式地知道派生类SomeUnit

可以通过在基类上应用KnownTypeAttribute来修复此问题,从而显式声明反序列化程序应该知道的派生类。

[DataContract]
[KnownType(typeof(SomeUnit))]
public class BaseClass
{
    ...
}
[DataContract]
public class SomeUnit : BaseClass
{
    ...
}

无法在接口类型上应用[NowType]。然而,有一些选项可以支持这一点:

选项#1

使用包装协定来声明已知类型。

[DataContract]
[KnownType(typeof(SomeUnit))]
public class Wrapper
{
    [DataMember]
    public IUnit Value { get; set; }
}
[DataContract]
public class SomeUnit : IUnit
{
    ...
}

选项#2

为DataContractSerializer构造函数指定已知类型。

然而,这将需要您告诉服务结构使用您的自定义序列化程序。

选项#3

在配置文件(app.config)中指定已知类型,如下所述。

我知道这是一个有点老的话题,但在遇到这个问题并且不想使用KnowType方法之后(因为如果你有很多派生类型,它可能会变得有点混乱),我能够通过以下反射的使用成功地序列化我的消息:

[DataContract]
[KnownType("GetKnownTypes")]
public abstract class Event
{
    [DataMember]
    public DateTime AtTime { get; private set; }
    public Event()
    {
        AtTime = DateTime.Now;
    }
    private static Type[] GetKnownTypes()
    {
        return typeof(Event).Assembly.GetTypes()
            .Where(x => x.IsSubclassOf(typeof(Event)))
            .ToArray();
    }
}