1

I have a problem regarding NewtonSoft.

I have a solution with 3 projects for example. Project A has reference points to Project B and Project C, Project B also has reference points to Project C. Both B and C has NewtonSoft assembly. Project C has function to get JsonMediaTypeFormatter:

new JsonMediaTypeFormatter()  

the function is called by all three project. Both Project B and C can call the function without any problem. But when project A calls the function, it throws error:

Method not found: 'Void Newtonsoft.Json.Serialization.DefaultContractResolver.set_IgnoreSerializableAttribute(Boolean)' 

Something I notice that even project A does not have NewtonSoft reference, when project is built, the Newtonsoft.json.dll is copied to its bin\Debug folder. I guess it is because of Newtonsoft assembly is set to true for Copy Local optoin in both project B and C. If I manually delete this dll from Project A's bin\Debug folder, problem solved.

My question is why project A can hit the exception, and is there any solution except manually delete Newtonsoft dll from project A's bin\Debug folder? Set Copy Local to false is not a option because it will prevent dll deploying to their own bin folder for project B and C too.

Any suggestion would be appreciated.

Update

Here is my code snippet

using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
using System.Net.Http.Formatting;

var jsonSerializerSettings = new JsonSerializerSettings
{
    Formatting = Formatting.Indented,
    ContractResolver = new CamelCasePropertyNamesContractResolver()
};

var dateConverter = new IsoDateTimeConverter
{
    DateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'"
};

jsonSerializerSettings.Converters.Add(dateConverter);

var formatter = new JsonMediaTypeFormatter
{
    //SerializerSettings = jsonSerializerSettings
};

If I comment out SerializerSettings, it works fine.

If I uncomment this line, application will return such issue.

If I just pass in blank setting to it

var formatter = new JsonMediaTypeFormatter
{
    //SerializerSettings = new JsonSerializerSettings{}
};

I got error:

Method not found: 'Void System.Net.Http.Formatting.BaseJsonMediaTypeFormatter.set_SerializerSettings(Newtonsoft.Json.JsonSerializerSettings)'

I think it may be related to different System.Net.Http.Formatting references inside projects, but I checked reference setting, they are all point to file

packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll

This code resides in Project C. It only failed when called by Project A, project B and C can call it without any problem. Once I remove NewtonSoft.Json.dll from Project A bin\Debug folder, it works in project A calls too.

Do you know what happened? and how can I check if there still have different reference version conflicit in project?

Thanks,

Jerry
  • 316
  • 5
  • 11

3 Answers3

4

Here I finally got problem solved.

The reaon for this issue is that in project A, there is a reference library points to System.Net.Http.Formatting (5.2.3.0), which depends on Newtonsoft Joson version 6.0.0.0. You can check this on Assembly Explorer. I updated Newtonsoft to 8.0.0.0 recently and project B and C are referencing this version. When project is built, the Newtonsoft 8.0 has been copy to project A's output folder based on prject B and C (Copy Local is set to true). when application is running, it will throw error

System.IO.FileLoadException : Could not load file or assembly 'Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)

or in my debug mode, it throws

{"The 'CreateJsonSerializer' method threw an exception when attempting to create a JSON serializer."}

Solution:

Add app.config file in project A, including setting below, to redirect system assembly binding to correct NewtonSoft version

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
    <bindingRedirect oldVersion="0.0.0.0-8.0.0.0" newVersion="8.0.0.0" />
  </dependentAssembly>
</assemblyBinding>

The reason project B can call project C successfully is that it has this redirect on its web.config file.

Thanks,

Jerry
  • 316
  • 5
  • 11
1

I would clean up the way you do references...in the "new way".

You have the below setup, except for repositories.config and the 3 packages.config

\SolutionFolder\
\SolutionFolder\MySolution.sln
\SolutionFolder\packages\
\SolutionFolder\packages\repositories.config

\SolutionFolder\CSProjectA\
\SolutionFolder\CSProjectA\CSProjectA.csproj
\SolutionFolder\CSProjectA\packages.config

\SolutionFolder\CSProjectB\
\SolutionFolder\CSProjectB\CSProjectB.csproj
\SolutionFolder\CSProjectB\packages.config

\SolutionFolder\CSProjectC\
\SolutionFolder\CSProjectC\CSProjectC.csproj
\SolutionFolder\CSProjectC\packages.config

Each of the packages.config will look like this

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="Newtonsoft.Json" version="4.5.11" targetFramework="net45" />
</packages>

repositories.config will look like this

<?xml version="1.0" encoding="utf-8"?>
<repositories>
  <repository path="..\CSProjectA\packages.config" />
  <repository path="..\CSProjectB\packages.config" />
  <repository path="..\CSProjectC\packages.config" />  
</repositories>

When you do a nuget restore, the following will be created

\SolutionFolder\packages\Newtonsoft.Json.4.5.11\
\SolutionFolder\packages\Newtonsoft.Json.4.5.11\lib\
\SolutionFolder\packages\Newtonsoft.Json.4.5.11\lib\net40\
\SolutionFolder\packages\Newtonsoft.Json.4.5.11\lib\net40\
\SolutionFolder\packages\Newtonsoft.Json.4.5.11\lib\net40\Newtonsoft.Json.dll
\SolutionFolder\packages\Newtonsoft.Json.4.5.11\lib\net40\Newtonsoft.Json.xml

All your .csproj references (hintpath) will be

..\packages\Newtonsoft.Json.4.5.11\lib\net40\Newtonsoft.Json.dll

This is what nuget does for you (auto-voodoo-magically), but I'm explaining it here.

This is how you get consistency from your references.

On your local box, you can just do a normal VS "build" or "rebuild". If you have missing packages, you can fix it (one time) with this command line call:

nuget.exe restore "\SolutionFolder\MySolution.sln"

When you build (on your build server), you will do a:

nuget.exe restore "\SolutionFolder\MySolution.sln"

msbuild.exe "\SolutionFolder\MySolution.sln"

APPEND

Try this:

"%WINDIR%\Microsoft.NET\Framework\v4.0.30319\msbuild.exe" "MySolution.sln" /p:Configuration=Debug;FavoriteFood=Popeyes /l:FileLogger,Microsoft.Build.Engine;logfile=MySolution.Debug.log "%WINDIR%\Microsoft.NET\Framework\v4.0.30319\msbuild.exe" "MySolution.sln" /p:Configuration=Release;FavoriteFood=Popeyes /l:FileLogger,Microsoft.Build.Engine;logfile=MySolution.Release.log

And view the log to see the source of the Newtonsoft.Json.dll is coming from (that ends up in ProjectA\bin\Debug).

Now that I relook at your comments and OP, you do have a weird problem. I'm wondering if the ProjectA\bin\Debug\Newtonsoft.Json.dll might be coming from an alternate source.

granadaCoder
  • 26,328
  • 10
  • 113
  • 146
  • Thanks for your help. I usually build solution in vs2015, with 'Allow NuGet to download missing packages' option checked, which I think it will do the same thing as nuget restore. I also have newtonsoft installed in package folder and both .csproj in project B and C reference to it. This cannot prevent build from copying newtonsoft to project A output, which causes this exception happens. But I do appreciate your comments. Thanks, – Jerry May 05 '16 at 05:05
  • //quote " function is called by all three project. " //end-quote Thus ProjectA should have a proper reference to Newtonsoft. If ProjectA has a reference to ProjectB and/or ProjectC, then OF COURSE (and correctly) the /bin/Debug or bin/Release directory is going to get a copy of Newtonsoft. – granadaCoder May 05 '16 at 12:56
  • quote " 'Allow NuGet to download missing packages' " end-quote... Make sure you read this http://docs.nuget.org/consume/package-restore/migrating-to-automatic-package-restore You don't want to mix the old-way and the new-way. – granadaCoder May 05 '16 at 13:04
  • I added an "APPEND" to my answer. – granadaCoder May 05 '16 at 14:02
  • I just update my question above. Thanks @granadaCoder – Jerry May 05 '16 at 21:36
0

I have the same problem. Project A (web app) reference project B (PCL), both have the same newtonsoft nuget package, and A has the binding redirect. Project C (test project) reference project B and E (PCL too), all having the same newtonsoft nuget package.

When i build project A, project A works ok. IF i build (not rebuild) project C, project E is build a,d project B is skipped (alreadu built). BUT project A is affected: something overwrites the newtonsoft json DLL in its bin folder with a CL version. And now project A won't run with this method not found error.

If i manually replace the newtonsoft json dll in project A with the same one that was in the bin folder before building project C, A works again ok !

If i then start debugging project C, no rebuild occurs, but project A stop working !

I suppose something is wrong with the newtonsoft json assembly between the PCL version and the net45 version, and the .NET engine picks the wrong one. I have added the net45 version to the test project, without success.

UPDATE ------------

The only workaround i found, is to separate projects in 2 solutions and open 2 visual studio. In solution A, i add project A and B. In solution B, i add project C and its dependancies B and E.

And now all works as expected. Project A can run, and running/compiling project B does not interfere with project A.

Softlion
  • 12,281
  • 11
  • 58
  • 88