Question

Context: I'm building a solution on AppHarbor, which invokes msbuild basically like this (docs) :

msbuild solution.sln /p:Configuration=Release /property:OutDir=C:\temp

To simplify the scenario somewhat, say I have these three projects in my solution.

  • A is a .NET 4.5 project referencing Newtonsoft.Json(.NET 4.5)
  • B is a Portable Class Library referencing Newtonsoft.Json(PCL)
  • C is a PCL referencing B

At the point of building C, I'm seeing an MSbuild error:

C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Microsoft.Common.targets(1605,5): warning MSB3268: The primary reference "B" could not be resolved because it has an indirect dependency on the framework assembly "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" which could not be resolved in the currently targeted framework. ".NETPortable,Version=v4.0,Profile=Profile47". To resolve this problem, either remove the reference "B" or retarget your application to a framework version which contains "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089". [C]

This is what I think happens:

  • B is built. B is compiled with a reference to Netwonsoft.Json(PCL), which is copied to OutDir
  • A is built and the Newtonsoft.Json(.NET 4.5) that it references is copied along with it to the OutDir, overriding the previous PCL version. Note that B would still be "runnable", because NuGet advises package authors that more specific versions of a library must be API compatible (and carry same assembly name and strong name).
  • C is built, however when it resolves the closure of assembly references, it would resolve B's Newtonsoft.Json(PCL) reference to Newtonsoft.Json(.NET 4.5) which in turn references mscorlib 4.0 instead of the retargetable mscorlib required by PCLs. Boom.

What I'm looking for is a way to work around this problem. I can't change the way AppHarbor builds the solution (so no changes to the msbuild commandline) and B and C must remain portable class libraries. A solution might involve either forcing a fixed build order or preventing the OutDir to end up in the AssemblySearchPaths when C is built. I'm open for suggestions though.

Or possibly I could make NuGet install Newtonsoft.Json into A in a way that uses the PCL version? Not sure if this would break other libraries that A depends on and that depend on Newtonsoft.Json in turn.

Was it helpful?

Solution

I have found a solution (after some digging) for this problem, please note that it requires MSBuild shipped with .NET 4.5 or later.

Microsoft added the property GenerateProjectSpecificOutputFolder, which will add a subdirectory with the project name under OutDir when set. To solve the problem above, I set the property to True in every PCL project in my solution. Since the plain .NET projects in my solution have project references to those PCLs, they will still be copied to the OutDir during the build, while the PCLs the selves are being built "in isolation".

Here's how to set the property by example (I'm including this project file instead of Microsoft.Portable.CSharp.targets):

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <!--When building in AppHarbor, we need a project specific output folder so the assembly references don't clash with those from the plain .NET projects-->
    <GenerateProjectSpecificOutputFolder>true</GenerateProjectSpecificOutputFolder>
  </PropertyGroup>

  <Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
</Project>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top