My name is Rex Morgan and I'm a Staff Software Engineer in Austin, TX working at Indeed.

I love learning new languages and tinkering with new technologies. I'm currently having fun with Elixir, Java, C#, and Kubernetes.

Using ILMerge to hide Dependencies

A few days ago I needed to install a nuget package to get some work done. Unfortunately, it depends on a higher version of Newtonsoft.Json than what we were currently using. I briefly looked into upgrading the version of Newtonsoft.Json across the application, but that ended up looking like more work than the original task I was working on.

After thinking about it a little more, I was asking myself, why I should even have to care that a package I want to take a dependency on is relying on something else? Why should I need to setup assembly bindings to try to redirect dependent assemblies to higher or lower versions based on what the rest of my application is running?

Then the idea hit me to ditch the nuget package all together. I decided to grab the assembly I wanted to use, and the version of Newtonsoft.Json that it depends on and merge them into one. This allows me to have a single assembly without having to worry about whether or not it's dependencies are going to play nice with the rest of the application.

To do this, I put the two assemblies I wanted to merge into a folder, renamed the original assembly to <assembly>.old.dll and ran the following command.

ILMerge.exe /out:<assembly>.dll /internalize /target:library /targetplatform:v4,C:\Windows\Microsoft.net\Framework64\v4.0.30319 .\<assembly>.old.dll .\Newtonsoft.Json.dll

Here's a breakdown of what that command does:

  • /out:<assembly>.dll outputs the result to <assembly>.dll.
  • /internalize marks all assemblies that are being merged into the first specified assembly as internal. This is important, as it makes sure we don't have duplicate namespaces with our other reference to Newtonsoft.Json.
  • /target:library tells ILMerge that we're merging assemblies, you can also use /target:exe if you're merging into an executable.
  • /targetplatform:v4,C:\Windows\Microsoft.net\Framework64\v4.0.30319 lets ILMerge know that the new assembly should target .NET 4.
  • .\<assembly>.old.dll this is the first assembly that we specify, so it's going to be the one that's not marked as internal. This should always be the main dependency that you want access to from your application.
  • .\Newtonsoft.Json.dll this is the assembly you want to merge in.
  • .\<another_assembly>.dll You can tack on as many assemblies at the end as you want. It will merge them all into a single dll.

After the merge was complete, I was able to add a reference to the produced dll. This worked just like the nuget package version, except I didn't have to worry about the Newtonsoft.Json dependency, at all.

In the near future, I'm planning on submitting a pull request to the repository of the nuget package that I had issues with. Hopefully if it's accepted the nuget package will no longer have any dependencies and will be a little easier to work with.

On the surface, this seems like a great way to deal with dependencies of nuget packages. However, I feel like since it's not wide-spread and we're all still dealing with these upgrade issues that there's a catch I'm not seeing. Let me know on twitter or by email what I'm missing.