-
Notifications
You must be signed in to change notification settings - Fork 62
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to access parent BinarySerializer inside IBinarySerializable? #158
Comments
I would recommend treating the encrypted payload as another "layer" in your protocol and using a second binary serializer. It's not really meaningful to get a reference to the parent inside a custom object since the object graph in that parent doesn't include the encrypted layer, if that makes sense. I spent a fair amount of time actually trying to incorporate the concept of layers into the serializer for use cases like this and concluded that it's really more trouble than it's worth. Out of curiosity, why don't you want to define a new serializer? |
I'm not sure I understand - the packet definition remains the same (and cannot change as we are implementing a spec), however the bytes for the Contents are optionally encrypted, as specified in the header. The decrypting operation itself requires a series of client-specific keys that also needs to be passed in to the Decode() function somehow - not sure how to do that here (initially hoped to do that using a custom Context, but not sure how to do that with a IBinarySerialiable). We use Dependency Injection to inject an instance of the serializer into any code that needs it, however DI wouldnt be able to set a value inside the object being serialized. It would not be ideal to have to define it in multiple places and yes - we can use a factory instead, but the above problem with keys still exists. Right now, the best idea we came up with is to have the Message object implement a custom interface (i.e. "IPostProcessingSerializable") - something like this using the example above:
We use the BinarySerializer through a wrapper class BinaryMessageSerializer that could check if the type implements the IPostProcessingSerializable interface and call PostSerialize()/PostDeserialize() to trigger processing of the stream. |
Yeah, I'm not suggesting changing the protocol, but treating the encrypted part as a "payload" byte[] field. Then take that field, decrypt it, and process it with a serializer. |
Thank you for the suggestions. In the end, used a wrapper for the serializer and broke the message down in pieces, decrypting the Contents piece when necessary. I think one helpful feature that would have made all of this much easier is to support passing in the instance of the object to set the values of, instead of creating it. So instead of
This would allow you to create the object in any way you liked, passing in whatever else was necessary, so serialization could make use of this, as necessary. |
I'm not sure I understand. If you already have the message, what would be the utility in deserializing it? How would the deserializer know which fields are meant to be kept? |
The object can be created to contain just about anything else you like and the serializer can have the following options:
Here is an example, although a bit silly one, but just to demonstrate this:
And usage:
Obviously the objects can contain any information that does not get serialized like factories that can tell an IBinarySerializable how to deserialize something (i.e. if data is encrypted). |
I think this might have been nicer to do if you used some of the SubType handling... public class Message
{
[FieldOrder(0)]
public MessageHeader Header { get; set; }
[FieldOrder(1)]
[SubType(nameof("Header")+"."+nameof(MessageHeader.IsEncrypted), false, typeof(MessageContent))]
[SubType(nameof("Header")+"."+nameof(MessageHeader.IsEncrypted), true, typeof(EncryptedMessageContent))]
public IMessageContents Contents { get; set; }
...
} and then you'd have something like public class EncryptedMessageContent : MessageContent, IBinarySerializable
{
void Deserialize(Stream stream,....)
{
// do the reading in of all the encrypted bytes.. and write out the decrypted bytes to a
// Memory stream, you can then use an instance of the BinarySerializer to deserialize the memory stream
// back to an instance of a MessageContent class, and use a mapper (AutoMapper, or similar) to apply it back to the
// EncryptedMessage fields (which it inherited as a child of MessageContent)...
var memStream = DecryptMessageContent(stream);
messageContent = serializer.Deserialize(memStream);
if (messageContent is MessageContent)
{
this = messageContent;
// we might be able to reach up through the context to access the parent and set the value in the header
// to IsEncrypted = false now... since we've decrypted it.
}
else
throw new Exception("Decryption failed");
}
void Serialize(Stream stream...)
{
// we don't really want to re-encrypt
var messageContent = this as MessageContent;
serializer.Serialize(stream, messageContent);
}
} |
Hello!
We receive messages where message headers are not encrypted and the payload is optionally encrypted. Whether the message is encrypted is indicated in the message header:
In order to be able to get access to the raw stream of data, the message payload is defined as an IBinarySerializable:
After we decrypt the raw stream, we want to use BinarySerializer to parse the decrypted contents, but we dont want to define a new BinarySerializer at this level and would rather make use of the one that initiated the deserialization operation at top-level:
Thank you!
The text was updated successfully, but these errors were encountered: