Skip to content
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

Question about generic serialization #36

Closed
bj0 opened this issue Jun 28, 2013 · 4 comments
Closed

Question about generic serialization #36

bj0 opened this issue Jun 28, 2013 · 4 comments

Comments

@bj0
Copy link

bj0 commented Jun 28, 2013

Here's a contrived example to demonstrate my question:

Say I have some messages defind by their payloads, and a generic envelope
that I stick a payload in and send/receive with. This is generally how I would
structure that classes:

class RequestMessage
{
    [YamlAlias('request')]
    string Request { get; set }

    [YamlAlias('requester_name')]
    string RequesterName { get; set; }
}

class ConfigMessage
{
    [YamlAlias('a')]
    string SettingA { get; set; }

    [YamlAlias('b')]
    int SettingB { get; set; }
}


class MessageEnvelope<TPayload>
{
    [YamlAlias('message_type')]
    string Type { get; set; }

    [YamlAlias('payload')]
    TPayload Payload { get; set; }
}

One issue I've been trying to figure out is how do you make this work well
with serialization, or more accurrately deserialization. If I create and object
and serialize it like so:

var ys = new Serializer();
var sr = new StringWriter();

var msg = new MessageEnvelope<ConfigMessage>(){
        Type="config", 
        Payload = new ConfigMessage(){
            SettingA = "red",
            SettingB = 5
            }
        };

ys.Serialize(sr, msg);

sr.ToString().Dump();

Ideally it creates yaml documents that looks like:

---
message_type: request
payload:
    request: alpha
    requester_name: bob
...

---    
message_type: config
payload:
    a: red
    b: 5
...

Which it does now (I just tested, it use to just give 'payload: {}', but must
have been fixed in a recent update).

The question is, how do you deserialize this in one pass to an object, when you
don't know what the payload type is before deserializing?

Currently I'm treating the payload as a separate serialized object, which yields
yaml like this:

---
message_type: request
payload: 'request: alpha\nrequester_name: bob\n\n'
...

---
message_type: config
payload: 'a: red\nb: 5\n\n'
...

This isn't nearly as clean and readible, and I was hoping for a good way to
do this, does anyone have any ideas?

@aaubry aaubry closed this as completed Aug 30, 2016
@jmo-gelsight
Copy link

This is marked as "completed". May I ask, how was this completed? Because I am facing the same issue.

@EdwardCooke
Copy link
Collaborator

I bet it was marked as complete because it serializes the object correctly. As for deserialization, that could be a bit trickier. You would need to build some kind of type factory or something that would read the yaml and determine what kind of object to create. We couldn't do that in yamldotnet for you, I do know that the extension points are there to do it. I'll see if I can drudge up an example. Until then, here is a working example where it serializes/deserializes (when you know the data type)

using System;
using System.Text.Json;
using YamlDotNet.Serialization;

var serializer = new SerializerBuilder()
    .Build();
var deserializer = new DeserializerBuilder()
    .Build();
var msg = new MessageEnvelope<ConfigMessage>()
{
    Type = "config",
    Payload = new ConfigMessage()
    {
        SettingA = "red",
        SettingB = 5
    }
};

var yaml = serializer.Serialize(msg);
Console.WriteLine(yaml);
Console.WriteLine("=====");
var deserialized = deserializer.Deserialize<MessageEnvelope<ConfigMessage>>(yaml);
Console.WriteLine(JsonSerializer.Serialize(deserialized));

class RequestMessage
{
    [YamlMember(Alias = "request")]
    public string Request { get; set; }

    [YamlMember(Alias = "request")]
    public string RequesterName { get; set; }
}

class ConfigMessage
{
    [YamlMember(Alias = "a")]
    public string SettingA { get; set; }

    [YamlMember(Alias = "b")]
    public int SettingB { get; set; }
}


class MessageEnvelope<TPayload>
{
    [YamlMember(Alias = "message_type")]
    public string Type { get; set; }

    [YamlMember(Alias = "payload")]
    public TPayload Payload { get; set; }
}

With the following output

message_type: config
payload:
  a: red
  b: 5

=====
{"Type":"config","Payload":{"SettingA":"red","SettingB":5}}

@EdwardCooke
Copy link
Collaborator

I think this will answer your question about how to determine what type to use based on a value of a scalar

#605

@jmo-gelsight
Copy link

This reply went above and beyond and is extremely helpful. Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants