Azure Service Fabric uses DataContract
serialization, which is a total disaster – it violates LSP (wiki) - see all those KnownTypeAttribute
things, making framework development basically impossible.
I made the following class be a parent of all ValueObject
to convince Service Fabric actually consume Binary serialization when it thinks about Data Contract one:
[DataContract]
[Serializable]
[JsonObject(MemberSerialization.OptOut)]
public abstract class SerializableObject
{
[DataMember]
[JsonIgnore]
byte[] State { get; set; }
static object Recursive { get; } = new object();
[OnSerializing()]
void OnSerializing(StreamingContext context)
{
if (context.Context == Recursive)
return;
var formatter = new BinaryFormatter(null, new StreamingContext(StreamingContextStates.Other, Recursive));
using (var stream = new MemoryStream())
{
formatter.Serialize(stream, this);
State = stream.ToArray();
}
}
[OnDeserialized()]
void OnDeserialized(StreamingContext ctxt)
{
if (State == null)
return;
var formatter = new BinaryFormatter();
using (var stream = new MemoryStream(State))
Assign(formatter.Deserialize(stream));
}
void Assign(object obj)
{
foreach (var property in GetType()
.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
.Where(p => p.CanRead && p.CanWrite))
property.SetValue(this, property.GetValue(obj));
}
}
So, actual objects could be something like this:
[DataContract]
[Serializable]
public class PacketRecieved : SerializableObject
{
public PacketRecieved(DeviceId deviceId, InboundPacket packet)
{
DeviceId = deviceId;
Packet = packet;
}
public DeviceId DeviceId { get; private set; }
public InboundPacket Packet { get; private set; }
}
1 Answer 1
- You should probably remove empty braces inside attributes.
[OnSerializing()]
=>[OnSerializing]
. This loop is very hard to read due to how you use offsets.
foreach (var property in GetType() .GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) .Where(p => p.CanRead && p.CanWrite)) property.SetValue(this, property.GetValue(obj));
Mainly because it is impossible to tell at first glace where
foreach
statement ends and loop body begins. Use offsets to separate them:foreach (var property in GetType() .GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) .Where(p => p.CanRead && p.CanWrite)) property.SetValue(this, property.GetValue(obj));
Or just add
{ }
braces (that's what I would do).State
is probably not the best name for a property, its too generic. MaybeSerializedState
orBinaryData
would do a better job at explaining its purpose.It would be nice to have some control over which properties are deserialized. You know, similar to how you can use
XmlIgnore
attribute to skip a property during xml (de-)serialization.- Unless what you do should be completely obvious to anyone working with Azure, you should add some basic documentation. I am not familiar with Azure, and to me it is unclear what problem you are trying to solve, why do you solve it using inheritance as opposed to using separate non-abstract binary serializer or wtf
Recursive
property is used for. You might want to explain some of those things in your code using xml-documentation.