General Problem
A lot of apps and libraries use NewtonsoftJson. So does buttplug-csharp
But there are a few problems:
- buttplug-csharp brings its own version of NewtonsoftJson (currently 13.0.4)
- a lot of .NET apps already bring their own version of NewtonsoftJson
- NewtonsoftJson does not seem to be forward compatible in some cases (see below)
- as far as I know, only one version of the library can be loaded
This is a problem for modding. The version conflict can lead to errors at runtime, even if the DLL is loaded fine at first.
My Specific Problem
The latest buttplug-csharp version (5.0.1-beta2, 08b2928) does not work with the game I'm trying to mod.
I'm getting the following error when calling ConnectAsync():
MissingMethodException: Method not found: string Newtonsoft.Json.Linq.JToken.ToString(Newtonsoft.Json.Formatting)
Stack trace:
Buttplug.Client.ButtplugConnectorJSONParser.Serialize (Buttplug.Core.Messages.ButtplugMessage msg) (at Buttplug/Client/ButtplugConnectorJSONParser.cs:29)
Buttplug.Client.ButtplugRemoteJSONConnector.PrepareMessage (Buttplug.Core.Messages.ButtplugMessage msg, System.Threading.CancellationToken token) (at Buttplug/Client/ButtplugRemoteJSONConnector.cs:41)
Buttplug.Client.ButtplugWebsocketConnector.SendAsync (Buttplug.Core.Messages.ButtplugMessage msg, System.Threading.CancellationToken cancellationToken) (at Buttplug/Client/ButtplugWebsocketConnector.cs:103)
Buttplug.Client.ButtplugClientMessageHandler.SendMessageAsync (Buttplug.Core.Messages.ButtplugMessage msg, System.Threading.CancellationToken token) (at Buttplug/Client/ButtplugClientMessageHandler.cs:35)
Buttplug.Client.ButtplugClient.ConnectAsync (Buttplug.Client.IButtplugClientConnector connector, System.Threading.CancellationToken token) (at Buttplug/Client/ButtplugClient.cs:133)
The issue is, that an overload of JToken.ToString() has been added between NewtonsoftJson release 13.0.4 and 13.0.2:
- in 13.0.2, there is:
ToString()
ToString(Formatting formatting, params JsonConverter[] converters)
- in 13.0.4, there is:
ToString()
ToString(Formatting formatting) <-- this overload is new
ToString(Formatting formatting, params JsonConverter[] converters)
While I believe that this is a bug in NewtonsoftJson (because it breaks compatibility in a patch release), I think we have to deal with it now. The versions are already released and used in games.
Solution?
Is there a recommended way to deal with this?
I can see the following possible solutions:
- ensure buttplug-csharp is compatible with a wide range of versions of NewtonsoftJson (how?)
- vendor NewtonsoftJson / rename the dependency to avoid conflicts
- use a different / custom JSON library
In my case, I was able to "fix" it by compiling buttplug-csharp myself and setting the NewtonsoftJson version to exactly the same version that the game uses when compiling. But that means I have to use a custom build.
General Problem
A lot of apps and libraries use NewtonsoftJson. So does buttplug-csharp
But there are a few problems:
This is a problem for modding. The version conflict can lead to errors at runtime, even if the DLL is loaded fine at first.
My Specific Problem
The latest buttplug-csharp version (5.0.1-beta2, 08b2928) does not work with the game I'm trying to mod.
I'm getting the following error when calling
ConnectAsync():The issue is, that an overload of
JToken.ToString()has been added between NewtonsoftJson release 13.0.4 and 13.0.2:ToString()ToString(Formatting formatting, params JsonConverter[] converters)ToString()ToString(Formatting formatting)<-- this overload is newToString(Formatting formatting, params JsonConverter[] converters)While I believe that this is a bug in NewtonsoftJson (because it breaks compatibility in a patch release), I think we have to deal with it now. The versions are already released and used in games.
Solution?
Is there a recommended way to deal with this?
I can see the following possible solutions:
In my case, I was able to "fix" it by compiling buttplug-csharp myself and setting the NewtonsoftJson version to exactly the same version that the game uses when compiling. But that means I have to use a custom build.