using ILMerge with .NET 4 libraries

Sarah Vessels picture Sarah Vessels · Jun 2, 2010 · Viewed 57.2k times · Source

Two problems:

1) Basic .NET Assembly Not Included in ILMerged Assembly

I'm having trouble using ILMerge in my post-build after upgrading from .NET 3.5/Visual Studio 2008 to .NET 4/Visual Studio 2010. I have a Solution with several projects whose target framework is set to ".NET Framework 4". I use the following ILMerge command to merge the individual project DLLs into a single DLL:

if not $(ConfigurationName) == Debug
  if exist "C:\Program Files (x86)\Microsoft\ILMerge\ILMerge.exe"
    "C:\Program Files (x86)\Microsoft\ILMerge\ILMerge.exe"
      /lib:"C:\Windows\Microsoft.NET\Framework64\v4.0.30319"
      /lib:"C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\PublicAssemblies"
      /keyfile:"$(SolutionDir)$(SolutionName).snk"
      /targetplatform:v4
      /out:"$(SolutionDir)bin\development\$(SolutionName).dll"
      "$(SolutionDir)Connection\$(OutDir)Connection.dll"
      ...other project DLLs...
      /xmldocs 

If I leave off specifying the location of the .NET 4 framework directory, I get an "Unresolved assembly reference not allowed: System" error from ILMerge. If I leave off specifying the location of the MSTest directory, I get an "Unresolved assembly reference not allowed: Microsoft.VisualStudio.QualityTools.UnitTestFramework" error.

The ILMerge command above works and produces a DLL. When I reference that DLL in another .NET 4 C# project, however, and try to use code within it, I get the following warning:

The primary reference "MyILMergedDLL" could not be resolved because it has an indirect dependency on the .NET Framework assembly "mscorlib, Version=4.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" which has a higher version "4.0.65535.65535" than the version "4.0.0.0" in the current target framework.

If I then remove the /targetplatform:v4 flag and try to use MyILMergedDLL.dll, I get the following error:

The type 'System.Xml.Serialization.IXmlSerializable' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.

It doesn't seem like I should have to do that. Whoever uses my MyILMergedDLL.dll API should not have to add references to whatever libraries it references. How can I get around this?

2) TypeLoadException Only When Using Merged Assembly

Edit: beyond this, even if I do add a reference to System.Xml in the consumer project that uses MyILMergedDLL.dll, making use of some code in MyILMergedDLL.dll gives this exception:

System.TypeLoadException: Could not load type 'System.Func`2' from assembly 'MyILMergedDLL, Version=1.0.1.1, Culture=neutral, PublicKeyToken=...'.

This is the code in my consumer project; the line that caused the TypeLoadException is the second one:

var keys = new[] {"a", "b", "c"};
var row = new Row(keys);

The particular Row constructor that throws the TypeLoadException is defined in a public class in MyILMergedDLL, and when I use this constructor when referencing the individual project DLLs, it works fine. It is only when I use this constructor when referencing the IL-merged DLL that I get the exception. I don't know what's going on.

Here's that constructor:

public Row(IEnumerable<string> keys) : base(keys) { }

And the base to which it is referring has this code:

foreach (string key in keys.Where(
    key => !string.IsNullOrEmpty(key)
))
{
    _dic.Add(key, string.Empty);
}

Answer

Hans Passant picture Hans Passant · Jun 3, 2010

There was a very recent release to solve x64 problems. Get in touch with Mike Barnett directly if you still have problems (mbarnett at microsoft dot com)


Addendum. There's something very, very wrong about your /lib:"C:\Windows\Microsoft.NET\Framework64\v4.0.30319" option. This has been getting lots of programmers in trouble lately, after .NET 4.5 was released. That directory is not the proper one for .NET 4.0 reference assemblies. Its content gets overwritten with the 4.5 assemblies, you can no longer use it to target a .NET 4.0 install. The runtime error you get is very awkward, the program cannot find certain types anymore. Usually bombing on the [Extension] attribute, sometimes on the ICommand interface.

These types, and some others, were moved from one assembly to another. Using the correct reference assemblies is a rock-hard requirement. You must use:

 /lib:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0"

Adjust to match your particular machine and target framework version.