0

I'm looking for a way to transform this c# object:

class BaseClass
{
    public string Value1 {get; set;}
    public NestedObject nestedObject {get;set;}
}

class NestedObject
{
    public string NestedValue1 {get; set;}
}

Into this json:

{
    "Value1": "value1",
    "NestedObject_NestedValue1": "nestedValue1"
}

By concatening the names of the nested parameters to their parent's name


Using normal serialization, this code: var json= JsonConvert.SerializeObject(baseClass);

Would instead return a json like this one:

{
    "Value1": "value1",
    "NestedObject": {
        "NestedValue1": "nestedValue1"
    }
}

I am sceptical about there being a way to deserialize a json like that back to an object tho.


Update:

As some asked what is the reason I'm trying to accomplish this: The reason I asked this question is because I serialize this object to send as json metadata to a service that only allows referencing top level propreties in a way similar to this:

[Metadata_Value1] would return "value1"

However [Metadata_NestedObject_NestedValue1] doesn't work and there isn't any indication to there being a way to reference nested properties.

Taking this in consideration I hoped there would be some solution that would allow keeping the nested objects in my program but transforming them all to top properties when sending them to this service.

In the service I would then be able to do: [NestedObject_NestedValue1] and get the value "nestedValue1"

Eldar
  • 9,781
  • 2
  • 10
  • 35
nku jomiru
  • 11
  • 1
  • Why do you want to do this? Is it just because of your concerns about deserializing back into an object? – tnw Sep 24 '20 at 17:34
  • What is the problem you're trying to solve here? This sounds like an X/Y problem. – Lasse V. Karlsen Sep 24 '20 at 17:37
  • Why not take a minute or two to see, *for a fact*, if there is an issue deserializing back into objects? – Ňɏssa Pøngjǣrdenlarp Sep 24 '20 at 17:47
  • "I am sceptical about there being a way to deserialize a json like that back to an object tho." You should try it. I've never had any issues, and if there are issues, it won't be the way JsonConvert serializes objects. It's designed to go both ways. – Audiopolis Sep 24 '20 at 17:52
  • @ŇɏssaPøngjǣrdenlarp That's because I don't know about a way to do it, and, if it would be possible to create a custom serializer that would modify the name of the propreties in such a way, it might be possible to find a solution for deserializing as well – nku jomiru Sep 25 '20 at 13:34
  • @LasseV.Karlsen I posted an update as to why I'm looking for such a solution – nku jomiru Sep 25 '20 at 13:45

1 Answers1

0

You can utilize a custom converter that looks like below :

public class NestedJsonConverter : JsonConverter
    {
        private readonly Type[] _types;
        public NestedJsonConverter(params Type[] types)
        {
            _types = types;
        }

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            JToken t = JToken.FromObject(value);
            if (t.Type != JTokenType.Object)
            {
                t.WriteTo(writer);
            }
            else
            {
                JObject o = (JObject)t;
                writer.WriteStartObject();
                void writeNested(JObject target, object source, string prefix)
                {
                    target.Properties().ToList().ForEach(p =>
                    {
                        var prop = source.GetType().GetProperty(p.Name);
                        var value = prop.GetValue(source);
                        var prefixed = string.IsNullOrEmpty(prefix) ? p.Name : $"{prefix}_{p.Name}";
                        if (p.Value.Type == JTokenType.Object)
                        {
                            writeNested((JObject)p.Value, value, prefixed);
                        }
                        else if (p.Value.Type == JTokenType.Array)
                        {
                            // you may need a more advanced handling in array scenarios
                            var arr = (JArray)p.Value;
                            writer.WritePropertyName(prefixed);
                            arr.WriteTo(writer);
                        }
                        else
                        {
                            writer.WritePropertyName(prefixed);
                            writer.WriteValue(value);
                        }
                    }

                    );
                }

                writeNested(o, value, "");
                writer.WriteEndObject();
            }
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            throw new NotImplementedException("Unnecessary because CanRead is false. The type will skip the converter.");
        }

        public override bool CanRead
        {
            get
            {
                return false;
            }
        }

        public override bool CanConvert(Type objectType)
        {
            return _types.Any(t => t == objectType);
        }
    }

Dotnetfiddle

Eldar
  • 9,781
  • 2
  • 10
  • 35