Controlling the JSON.NET Version used

The full version of West Wind wwDotnetBridge includes support for JSON parsing and as such includes a reference to the popular JSON.NET library. This library is widely used and very reliable in parsing JSON into .NET objects. The wwJsonSerializer class uses this library to parse objects to .NET objects and then into FoxPro objects for an efficient and reliable way to provide a JSON parser. The wwDotnetBridge.ToJson() method, which can be used to create JSON from .NET objects, also uses JSON.NET for serialization.

As cool as JSON.NET usage in West Wind products is, there are also some issues.

Because JSON.NET is so widely used in .NET, it's quite likely that you will run into other .NET components that also use JSON.NET - and quite likely use a different version of it. Since .NET can only load one version of a given .NET library at any one time into the host process, this can cause a problem as one component may not be able to load the version of JSON.NET that it's binding to.

.NET is a statically linked runtime environment so binaries are almost always tied to a specific version number of the component. So if you have two components or an application and components trying to use different versions of the same library there can be a conflict.

Luckily .NET provides a workaround for this in most situations.

Assembly Redirects to the Rescue

.NET has a built-in system for runtime version forwarding which can be accomplished by way of Assembly Redirects in the applications .config file.

For FoxPro applications this means you can specify these assembly redirects into one of these files:

  • YourApp.exe.config
  • VFP9.exe.config

The config file is associated with the launching .EXE file, so that's either your standalone compiled application file, or the FoxPro IDE vfp9.exe.

The following is an example of .config file that forces JSON.NET usage of any version to version 13.0:

<?xml version="1.0"?>
<configuration>
  <startup>   
	<!-- <supportedruntime version="v4.0.30319"/> -->
	<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
	<!-- supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" -->    
    <!-- supportedRuntime version="v2.0.50727"/ -->    
  </startup>
  <runtime>
      <loadFromRemoteSources enabled="true"/>
  </runtime>
  
  <runtime>    
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-14.0.0.0" newVersion="13.0.0.0" />
      </dependentAssembly>
	</assemblyBinding>      
  </runtime>
</configuration>
Assembly Version vs. File Version!

Important: The version number you need to specify is the Assembly Version not the File Version. Unfortunately the file version is what you see when you view File -> Properties -> Details. Most assemblies match assembly and file versions but some libraries like Newtonsoft.Json use fixed assembly versions with file version differentiators. So in this case the File Version is 13.0.0.3 while the Assembly version is 13.0.0.0 and the latter is the value that needs to be specified.

The key element is the <dependentAssembly> which describes Newtonsoft.Json and basically redirects any version found - oldVersion - to the newVersion. The new version in this case is the greater version number between the one wwDotnetBridge provides and whatever other higher version is in use.

You can find the Assembly Version number with a tool like Reflector (provided in the \Tools\Reflector directory) to look up the Assembly version number. There are other free tools like ILSpy and DotPeek. If you don't want to use these you can fall back to .dll version number in the File details (Explorer -> Right Click DLL -> Details) but be aware that this may not be the same as the Assembly version. If it doesn't work try rounding down to the x.0.0.0 version as that's typically what's used when File and Assembly versions are not synced.

In the example, here I'm interfacing with a .NET Socket.IO client library that uses Newtonsoft.Json version 8 and that's what's reflected in the newVersion. Now when wwDotnetBridge asks to version 6.0 of JSON.NET, .NET redirects to version 8.0 and everything works as long as the interface of the library supports the same signatures of methods and properties that the code accesses.

This approach works for any .NET assembly (dll) where there might be multiple versions in place.


© West Wind Technologies, 2024 • Updated: 07/31/24
Comment or report problem with topic