.NET Framework version hell on build server

TL;DR

When building a Visual Studio solution on a build server, make sure that directory C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework contains reference assemblies for ALL .NET versions targeted by your projects. Exact match is required: project targeting .NET 4.5 cannot use reference assemblies from v4.5.1. You can obtain reference assemblies by installing “.NET Framework x.y.z Developer Pack”.

More details

I have just run into this problem: the solution would not build locally, because project A targeting .NET 4.5 was referencing project B targeting 4.6.1. The reference was ignored with a warning, and all attempts to use classes from project B led to compiler errors. Amazingly, the same commit compiled perfectly well on our build server.

I don’t like to leave such mysteries unresolved, because they tend to come back and bite you at the very worst moment. So I was compelled to investigate. Skipping the gore details of my arduous ordeal, here’s the takeaway:

1. We use TeamCity’s “Visual Studio (sln)” target, in combination with Microsoft Build Tools 2015.

2. When building a project targeting .NET version 4.x, it will look in C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.x for reference .NET assemblies. This includes mscorlib.dll, System.dll and other framework assemblies.

3. If it cannot find reference assemblies for that specific version, it will issue a warning and use assemblies from the GAC, which typically means the latest .NET version installed on the machine.

4. Installing specific version of .NET framework does not change the reference assemblies, but does change assemblies in the GAC.

5. You can install reference assemblies via something call “developer pack”, e.g. “.NET Framework 4.6.2 developer pack”. Technically, you only need a “targeting pack” for your specific version, but I could not find stand-alone installation for a targeting pack, it only seems to come as part of a developer pack.

6. Developer packs for .NET 4.5.2, 4.6.1, and 4.6.2 can be obtained from Microsoft Download center. I could not find anything for 4.5: it probably comes with Visual Studio 2013. I just copied files from my machine to the build server machine, and it worked.

My particular situation

Remember, I had project A targeting .NET v4.5 and referencing project B that targets .NET 4.6.1.

Step 1

The build server had .NET 4.5.2 installed, and reference assemblies for 4.5.1 and 4.5.2.
As a result, both project were built against GAC (i.e. 4.5.2) without errors, but with the following warning:

Project A:
warning MSB3644: The reference assemblies for framework ".NETFramework,Version=v4.5" were not found. To resolve this, install the SDK or Targeting Pack for this framework version or retarget your application to a version of the framework for which you have the SDK or Targeting Pack installed. Note that assemblies will be resolved from the Global Assembly Cache (GAC) and will be used in place of reference assemblies. Therefore your assembly may not be correctly targeted for the framework you intend.

Project B:
warning MSB3644: The reference assemblies for framework ".NETFramework,Version=v4.6.1" were not found...

Step 2

I installed .NET framework 4.6.1 – just the runtime, not the reference assemblies. Both projects are now built against 4.6.2, with no errors and the same warnings as in step 2.

Step 3

I installed .NET Framework 4.6.1 Developer Pack. This installs reference assemblies. Now project A is built against the GAC (4.6.1) with a warning, and project B is built without a warning.

Step 4

I copied reference assemblies for .NET 4.5 from my machine to the build server. Now project A is built against .NET 4.5 with an error:

warning MSB3274: The primary reference ProjectB.dll could not be resolved because it was built against the ".NETFramework,Version=v4.6.1" framework. This is a higher version than the currently targeted framework ".NETFramework,Version=v4.5".

Project B is built without errors. This is the behavior I was receiving on my local machine all along.

Conclusion

Do ensure that ALL .NET versions you use appear in the reference assemblies folder. Otherwise, some binaries you build may not target .NET version they are supposed to target. Also, you may miss some .NET version mismatches in your projects.

6 Comments


  1. You are the best dude!!!!

    Reply

  2. Thanks for explanation, in fact this blog helped me understand many magical stuffs behind the scene.

    I have one small doubt though – It seems .net framework target packs are meant for build and compilation purpose only – But i am still wondering the motive for this design because on developer machine anyway .net runtime is required so why not msbuild use those assemblies directly during build. Is it just to have lightweight reference assemblies on build server ? I am sure there must be better supporting reasons for this.

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *