Search code examples
json.netassemblybinding

Resolving conflicting version requirements for NewtonSoft.Json


I have read several postings about assembly binding issues and have tried many of the proposed solutions, all with no luck.

I have a relatively old asp.net web forms web site. It depends on a .Net Framework 4.6 Analytics assembly that in turn depends on NewtonSoft.Json. That Analytics assembly is one of our own and was built with NewtonSoft.Json v7.0.1. That is the version of the assembly that resides in the web site's bin folder.

I have a newer web site, an Angular SPA, that relies on .Net Framework WebApi services. The services rely on a logging helper component that calls a separate logging service. The logging helper component depends on Microsoft.AspNet.WebApi.Client to make the service call, which depends on System.Net.Http.Formatting, which depends on NewtonSoft.Json v6.0.4.

When I try to use the new logging helper component in the web site, at runtime, the logging fails saying that it cannot load v6.0.0.0 of NewtonSoft.Json or one of its dependencies.

If I drop the v7.0 file in the web site bin folder, the web site fails because the Analytics assembly cannot load v7.0.0.0 of NewtonSoft.Json or one of its dependencies.

Ideally I'd like to have Microsoft.AspNet.WebApi.Client and System.Net.Http.Formatting play nicely with the newer version of NewtonSoft.Json, but I don't have much control over how those assemblies play. I've tried rebuilding my Analytics component with NewtonSoft.Json v6.0.4, but when it gets built and deployed, somehow on the web server it still ends up looking for v7.0.0.0.

I feel like I'm stuck between a rock and a hard place. I can either have my Analytics work or my Logging work, but I cannot get both to work. Any suggestions as to a) what direction to pursue for a solution - getting my Analytics component to accept the older version or getting my Logging component to work with the newer version and b) how to accomplish either of those approaches?

Update 1 - Some of the things I've tried beyond what I've described above: In my logging helper component .csproj project file, I tried eliminating the version information from my NewtonSoft.Json reference. I deployed it into the web site with the NewtonSoft.Json v7.0 file, but it still failed saying it couldn't load v6.0. I tried using fuslogvw.exe, the Assembly Binding Log Viewer. Maybe I wasn't using it right, but I could reproduce my assembly binding error and saw nothing at all the Assembly Binding Log Viewer.

Update 2 - I tried adding an assembly binding redirect in my logging helper component redirecting it from 6.0.0.0 to 7.0.0.0, but when I build the component and drop it in the web site bin folder, which now has the NewtonSoft.Json 7.0 file, the logger still fails saying that it can load v6.0.0.0. Is there no way out of this?

<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
  <dependentAssembly>
    <assemblyIdentity name="NewtonSoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral"/>
    <bindingRedirect oldVersion="6.0.0.0"
                     newVersion="7.0.0.0" />
  </dependentAssembly>
</assemblyBinding>

Update 3 - Below is the packages.config from the logging helper component. I believe that everything in packages.config is based on my adding the Microsoft.AspNet.WebApi.Client package. According to the package info on NuGet, it should work with NewtonSoft.Json >= 6.0.4, but it always fails looking for 6.0.0.0.

<packages>
    <package id="Microsoft.AspNet.WebApi.Client" version="5.2.6" targetFramework="net461" />
    <package id="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" version="1.0.5" targetFramework="net461" />
    <package id="Microsoft.Net.Compilers" version="2.4.0" targetFramework="net461" developmentDependency="true" />
    <package id="Newtonsoft.Json" version="6.0.4" targetFramework="net461" />
    <package id="System.Net.Http" version="2.0.20126.16343" targetFramework="net461" />
</packages>

Solution

  • I'm not entirely satisfied with this answer, but it does appear to work. I read through several more posts on this topic, specifically posts about issues with version conflicts with NewtonSoft.Json, which seems to have conflicts quite often. In this article several people reported that the assembly binding redirects only worked if they were in machine.config. I had been trying to add assembly binding redirects in my logging helper component config file. I realize now that since I had a runtime binding error, I needed to work on the configuration of the runtime application, i.e. the web site. But adding the bind redirects to web.config seems to have no effect, while adding them to machine.config works. Unfortunately it breaks other applications on the server that need a different version. So... sort of an answer, but not all the way there yet. Here is the binding redirect that, when added to machine.config on the web server, gets the logging helper component working correctly in the web site.

    <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="NewtonSoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral"/>
        <bindingRedirect oldVersion="6.0.0.0" newVersion="7.0.0.0" />
      </dependentAssembly>
    </assemblyBinding>
    </runtime>
    

    But I still need to figure out how to get the other applications on the server to work correctly. This problem seems to never end.

    Update: I have a working solution, at least in my Dev and Test environments. The solution involves the assembly binding redirect in machine.config as described above plus installing the desired version of the assembly into the Global Assembly Cache (GAC) so that it's available to all applications on the server.

    It's not my favorite solution and I'd still be happy to hear alternatives, but for now, this is what I've got and it seems to work. Only problem left is getting the assembly into the GAC on Production servers that don't have Visual Studio or Windows SDK installed - so no gacutil.exe utility.