Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Service Fabric Reliable Collections: serialization issue

Reliable Collection (Queue) values store some complex type SomeUnit.

I've marked it as [DataContract] and it's members as [DataMember] and added [KnownType(typeof(SomeUnit))] attribute on top of it also.

Looks like now SomeUnit serializes, but then deserialize exception is thrown:

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.

How can I solve it?

like image 801
AsValeO Avatar asked Dec 09 '15 03:12

AsValeO


1 Answers

Since you are not showing any code we can only guess what's causing this.

This problem would occur if you would use a reliable queue with a generalized item type, for example a base class of 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!

The deserializer for that queue would know how to parse BaseClass but it won't be implicitly aware of your derived class SomeUnit.

You can fix that by applying a KnownTypeAttribute on the base class, thereby explicitly declaring the derived classes that the deserializer shall be aware of.

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

[DataContract]
public class SomeUnit : BaseClass
{
    ...
}

It's not possible to apply [KnownType] on an interface type. There are, however, some options for supporting this:

Option #1

Use a wrapper contract to declare known type(s).

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

[DataContract]
public class SomeUnit : IUnit
{
    ...
}

Option #2

Specify known types to the DataContractSerializer constructor.

This will, however, require that you tell service fabric to use your custom serializer.

Option #3

Specify known types in a configuration file (app.config) as described here.

like image 167
Mårten Wikström Avatar answered Sep 27 '22 22:09

Mårten Wikström