3

I have studied several SO answers citing this exception (like this one) without success. Also, my example to reproduce the behavior is the most minimal that I've seen. As a control for reproducing this issue, I have this constant string:

const string json =
@"{
    ""ArrayOfString"": [""Hello World""]
  }";

And ClassA:

class ClassA
{
    public string[] ArrayOfString { get; set; }
}

There are no issues deserializing ClassA whether I do it with Newtonsoft.Json or System.Text.Json.

ClassA classA;
classA = Newtonsoft.Json.JsonConvert.DeserializeObject<ClassA>(json);
classA = System.Text.Json.JsonSerializer.Deserialize<ClassA>(json);

Now consider ClassB where the same property has a backing store in BaseClass.

class ClassB : BaseClass
{
    public string[] ArrayOfString
    {
        get => new string[] { base.SingularString };
        set
        {
            if((value != null) && (value.Length == 1))
            {
                base.SingularString = value[0];
            }
        }
    }
}
class BaseClass
{
    public string SingularString { get; set; } = "Hello World";
}

It doesn't seem like a big ask to have ClassB deserialize from the same json source.

ClassB classB;
classB = Newtonsoft.Json.JsonConvert.DeserializeObject<ClassB>(json);
classB = System.Text.Json.JsonSerializer.Deserialize<ClassB>(json);

Newtonsoft doesn't have any beef doing this:

newtonsoft watch

However, System.Text.Json throws when asked to do the same thing:

system.text.json

Does anyone have first-hand knowledge of this bug which was closed more than 2 years ago? Is this a reemergence of that? Or am simply making an error of some kind? And yeah, I get it. The collection is a fixed size but why would that matter?

IVSoftware
  • 5,732
  • 2
  • 12
  • 23
  • I can't reproduce on .NET 6, see https://dotnetfiddle.net/UhRYJP. What version are you using? ... According to [this pull](https://github.com/dotnet/corefx/pull/39442) the issue was fixed in .NET 5. – dbc Jun 24 '22 at 22:55
  • @dbc per tag it's .NET core 3.1. I'll go ahead and try it on 5/6 and see what's up. Thx. – IVSoftware Jun 25 '22 at 03:43
  • 1
    Confirmed. Works correctly with .NET 5 or .NET 6. Fails with .NET Core 3.1 (tried it in VS 2019 and VS 2022 with the same result). **You have answered my question** thank you that's the certainty I was looking for. – IVSoftware Jun 25 '22 at 04:03

1 Answers1

1

This is a bug that was fixed in .NET 5. See pull Replace collection instances on deserialize #39442. A working .NET 6 fiddle can be seen here: https://dotnetfiddle.net/UhRYJP.

If you must develop against .NET Core 3.1, your options would appear to include:

  1. Introduce a custom converter for ClassB.

  2. Use a List<string> instead of a string [] for ArrayOfString:

    class ClassB : BaseClass
    {
        public List<string> ArrayOfString
        {
            get => new List<string>() { base.SingularString };
            set
            {
                if((value != null) && (value.Count == 1))
                {
                    base.SingularString = value[0];
                }
            }
        }
    }
    

    (Note that if you are still targeting both System.Text.Json and Newtonsoft, List<string> will not work with the latter. See e.g. Why are all the collections in my POCO are null when deserializing some valid json with the .NET Newtonsoft.Json component for why.)

dbc
  • 104,963
  • 20
  • 228
  • 340