Newtonsoft Json package and ILStripping

When porting our project from standalone to webgl we’ve hit a wall with the Newtonsoft Json package for our TransferModel communication with our rest api servers. We’ve tried the 3.0.1 and 2.0.2 versions.

ILStripping causes Json deserialization to fail on certain constructs. First off we get no hints to what part of the json fails to serialize. After we’ve isolated the problem we’ve found ourselves unable to work around it.

A simple HashSet properties like this fails at runtime with absolutely no helpful debug information.

The runtime exception is straight up garbage.
Error details

System.ArgumentNullException: Value cannot be null.
Parameter name: method
at Newtonsoft.Json.Utilities.ValidationUtils.ArgumentNotNull (System.Object value, System.String parameterName)
at Newtonsoft.Json.Utilities.LateBoundReflectionDelegateFactory.CreateParameterizedConstructor (System.Reflection.MethodBase method)
at Newtonsoft.Json.Serialization.JsonArrayContract.CreateWrapper (System.Object list)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateNewList (Newtonsoft.Json.JsonReader reader, Newtonsoft.Json.Serialization.JsonArrayContract contract, System.Boolean& createdFromNonDefaultCreator)

The actual source code of the package is nowhere to be found, the link points to the non AOT public NewtonSoft.Json repo. But clearly LateBoundReflectionDelegateFactory.CreateParameterizedConstructor has been modified by Unity because the official version just tries to call the HashSet(ICollection data) constructor but keeping that in there didn’t work. Taking at look at the actual dll reveals that the culprit is
the invention of something called internal class CollectionWrapper. It turns out that the constructor CollectionWrapper<HashSet>.CollectionWrapper(ICollection list) is not available. Since the class is internal I can’t even manually reference it in my code and as such I see no way to work around this.

So please:

  • Add a simple try catch with some relevant debug information could tell us which part of the json parsing fails!
  • Stop hiding the source code for Open Source Projects! If I had code and could compile my own version of an open source project I could have fixed this in 30 minutes tops.
  • Stop making classes internal so we can’t reference them in code and prevent them from being stripped.

Needless to say making webgl builds is SLOW, so I’ve wasted a full day on this crap.

1 Like

I’m running into this same problem. Can’t deserialize HashSets anymore.

It’s super frustrating because Unity 2021.3 is supposed to be LTS but between 2021.3.1f1 and 2021.3.2f1 a breaking change was made where looking in the package dependencies, the package “com.unity.services.core” now directly depends on “com.unity.nuget.newtonsoft-json”.

I was using my own copy of newtonsoft json in my Assets folder, but because of Unity now requiring use of the nuget package, I had to delete my own copy in my Assets folder to fix the duplicate symbol errors.

Then my game crashes for some reason and I’ve tracked it down to not being able to deserialize HashSets from the game saves.

I’ve wasted a full day trying to fix this issue … just from upgrading a point version from 2021.3.1f1 to 2021.3.2f1 … dealing with stuff like this makes me want to pull my hair out! Why does Unity keep making breaking changes between point versions wasting our time so much?

Tried doing this, but still got errors at runtime:

Gonna have to call it a day.

1 Like

Found the solution in case anyone sees this:

If you get a:

System.ArgumentNullException: Value cannot be null.
Parameter name: method

You can fix it with this:

5 Likes

What a boss! I have a static save class so I just stuck this at the top of the constructor:

AotHelper.EnsureList<string>();
AotHelper.Ensure(() => _ = new HashSet<string>(new string[0]));
1 Like

Sorry for necroing this thread but I’m having the same problem and am about to implement the same solution.

Before I do though, does it make sense that I need to do this even though I’m already instantiating HashSet< string > (the type I’m crashing with on deserialize) elsewhere in my code?

Thanks,
Jeff

1 Like