2

I'm using dotnet core 2.1 and made a helper to serialize from and to JSON. It's built on System.Runtime.Serialization.Json that ships with dotnet core.

I don't want to use JSON.NET lib for some reasons (it doesn't matter here)

I'm facing a bug I don't understand, Here's the Helper class I made (I just left the ToJson method as this is the one where my issue occurs)

public static class JsonUtils
{
    private static readonly DataContractJsonSerializerSettings _jsonSettings = new DataContractJsonSerializerSettings
    {
        UseSimpleDictionaryFormat = true,
        SerializeReadOnlyTypes = true,
        EmitTypeInformation = EmitTypeInformation.Never
    };

    public static string ToReadableJson<T>(T o)
    {
        string res = null;

        try
        {
            using (var ms = new MemoryStream())
            using (var writer = JsonReaderWriterFactory.CreateJsonWriter(ms, Encoding.UTF8, true, true, "  "))
            {
                var serializer = new DataContractJsonSerializer(typeof(T), _jsonSettings);
                serializer.WriteObject(writer, o);
                writer.Flush();

                ms.Position = 0;

                using (var sr = new StreamReader(ms))
                {
                    res = sr.ReadToEnd();
                }
            }
        }
        catch
        { }

        return res;
    }
}

Everything worked fine until I noticed recently that some objects are simply ignored if their properties have non public setter. I don't understand why a setter has to be public, it's just supposed to read data to serialize, right ?

Here's a little code to test :

public class TestSubObject
{
    public string Property { get; set; } = "Bar";
}

public class TestObject
{
    public TestSubObject Sub { get; set; }
    public string Property { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        var o = new TestObject
        {
            Property = "Foo",
            Sub = new TestSubObject()
        };

        string json = JsonUtils.ToReadableJson<TestObject>(o);
        Console.WriteLine(json);

        Console.Read();
    }
}

In this example, I just have a root object (TestObject) that have another complex object as property (TestSubObject)

In this case, it works :

OK

Then, If I change the TestSubObject.Property setter from public to private, it does not work anymore. (In my real case, the class is in another assembly with 'internal' set)

NOTOK

My Sub Property vanished.

As you can see, I checked the DataContractJsonSerializerSettings and already set the SerializeReadOnlyTypes to true, but this does not change anything.

Yes, I can edit my classes to be full public but I don't understand this, so I post it here, if anyone got an idea.

Thanks

kipy
  • 527
  • 4
  • 10
  • So... do you want the serialization to add data that the deserialization will be forced to ignore? - Addendum: or worse, throw because it can't set it. Perhaps serialization should throw, so you know of the problem earlier. – Theraot May 18 '19 at 20:08
  • "do you want the serialization to add data that the deserialization will be forced to ignore" -> that makes sense :) But yeah, these data are computed and don't have to be read from json. There's no exceptions thrown in both cases. I just removed unnecessary lines from my original code to simplify the example. Thank you for your answer – kipy May 18 '19 at 20:14

1 Answers1

4

When you use System.Runtime.Serialization without any annotations it will ignore properties that can't be set and serialize all public members of given type that can be serialized and deserialized.

However, if you go for explicit declaration of what it should serialize, it will work:

[DataContract]
public class TestSubObject
{
    [DataMember]
    public string Property { get; private set; } = "Bar";
}

[DataContract]
public class TestObject
{
    [DataMember]
    public TestSubObject Sub { get; set; }
    [DataMember]
    public string Property { get; set; }
}

Output:

{
  "Property": "Foo",
  "Sub": {
    "Property": "Bar"
  }
}
mwilczynski
  • 3,062
  • 1
  • 17
  • 27