Service Fabric Reliable Collections:序列化问题
Service Fabric Reliable Collections: serialization issue
可靠集合(队列)值存储一些复杂类型SomeUnit
。
我已将其标记为 [DataContract]
,其成员标记为 [DataMember]
,并在其顶部添加了 [KnownType(typeof(SomeUnit))]
属性。
看起来现在 SomeUnit 序列化了,但是反序列化异常被抛出:
Element 'urn:ServiceFabric.Communication:item' contains data from a
type that maps to the name
'http://schemas.datacontract.org/2004/07/RP.Core:SomeUnit'. The
deserializer has no knowledge of any type that maps to this name.
Consider using a DataContractResolver if you are using
DataContractSerializer or add the type corresponding to 'SomeUnit' to
the list of known types - for example, by using the KnownTypeAttribute
attribute or by adding it to the list of known types passed to the
serializer.
我该如何解决?
由于您没有显示任何代码,我们只能猜测是什么原因造成的。
如果您使用具有通用项类型的可靠队列,例如 SomeUnit
的基 class。
,则会出现此问题
// 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
但它不会隐含地知道您的派生 class SomeUnit
.
您可以通过在基础 class 上应用 KnownTypeAttribute
来解决这个问题,从而显式声明反序列化器应注意的派生 classes。
[DataContract]
[KnownType(typeof(SomeUnit))]
public class BaseClass
{
...
}
[DataContract]
public class SomeUnit : BaseClass
{
...
}
无法在接口类型上应用 [KnownType]。但是,有一些选项可以支持这一点:
选项#1
使用包装合约声明已知类型。
[DataContract]
[KnownType(typeof(SomeUnit))]
public class Wrapper
{
[DataMember]
public IUnit Value { get; set; }
}
[DataContract]
public class SomeUnit : IUnit
{
...
}
选项#2
将已知类型指定给 DataContractSerializer constructor。
但是,这需要您 tell service fabric to use your custom serializer。
选项 #3
在配置文件 (app.config) 中将已知类型指定为 described here。
我知道这是一个有点老的话题但是在遇到这个问题并且不想使用 KnownType 方法(因为如果你有很多派生类型它会变得有点混乱)我能够成功使用以下反射序列化我的消息:
[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();
}
}
可靠集合(队列)值存储一些复杂类型SomeUnit
。
我已将其标记为 [DataContract]
,其成员标记为 [DataMember]
,并在其顶部添加了 [KnownType(typeof(SomeUnit))]
属性。
看起来现在 SomeUnit 序列化了,但是反序列化异常被抛出:
Element 'urn:ServiceFabric.Communication:item' contains data from a type that maps to the name 'http://schemas.datacontract.org/2004/07/RP.Core:SomeUnit'. The deserializer has no knowledge of any type that maps to this name. Consider using a DataContractResolver if you are using DataContractSerializer or add the type corresponding to 'SomeUnit' to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding it to the list of known types passed to the serializer.
我该如何解决?
由于您没有显示任何代码,我们只能猜测是什么原因造成的。
如果您使用具有通用项类型的可靠队列,例如 SomeUnit
的基 class。
// 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
但它不会隐含地知道您的派生 class SomeUnit
.
您可以通过在基础 class 上应用 KnownTypeAttribute
来解决这个问题,从而显式声明反序列化器应注意的派生 classes。
[DataContract]
[KnownType(typeof(SomeUnit))]
public class BaseClass
{
...
}
[DataContract]
public class SomeUnit : BaseClass
{
...
}
无法在接口类型上应用 [KnownType]。但是,有一些选项可以支持这一点:
选项#1
使用包装合约声明已知类型。
[DataContract]
[KnownType(typeof(SomeUnit))]
public class Wrapper
{
[DataMember]
public IUnit Value { get; set; }
}
[DataContract]
public class SomeUnit : IUnit
{
...
}
选项#2
将已知类型指定给 DataContractSerializer constructor。
但是,这需要您 tell service fabric to use your custom serializer。
选项 #3
在配置文件 (app.config) 中将已知类型指定为 described here。
我知道这是一个有点老的话题但是在遇到这个问题并且不想使用 KnownType 方法(因为如果你有很多派生类型它会变得有点混乱)我能够成功使用以下反射序列化我的消息:
[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();
}
}