Nathan Palmer
Nathan Palmer

Reputation: 2030

How can I maintain two separate projects but merge them into one DLL?

I'm hoping that there is just something simple that I am missing here. I am trying to maintain two separate projects

ProjectName.Core &
ProjectName.Infrastructure

This is made in a typical Onion architecture so I can loosely couple my services and gain a greater flexibility. The Infrastructure project references the Core project. Once compiled they generate these DLLs

ProjectName.Core.dll &
ProjectName.Infrastructure.dll

But I would like to have it generate just 1 dll.

ProjectName.Infrastructure.dll (or even ProjectName.dll)

I have tried to use ILMerge to perform this operation but since Infrastructure references Core it throws an exception because it can't find the Core dll. It's obviously not looking within itself.

Now I need to maintain the separate projects because I have some other combinations that reference Core and another project that will be joined together such as

ProjectName.Core &
ProjectName.DataAccess &
ProjectName.Web

EDIT: My current solution calls out to ILMerge using an Nant build script. It merged together successfully. But when I try to use the merged DLL it throws an exception because it can't find the Core library.

  <target name="merge.core">
    <property name="temp.dir" value="${build.dir}\Temp\"/>
    <mkdir dir="${temp.dir}" if="${not directory::exists(temp.dir)}"/>
    <property name="tools.dir" value="&quot;${directory::get-current-directory()}\Tools\&quot;"/>
    <exec program="Tools\ILMerge\ILMerge.exe" workingdir=".">
      <arg value="/t:Library"/>
      <arg value="/ndebug"/>      
      <arg value="/out:&quot;${build.dir}\Temp\ProjectName.Infrastructure.dll&quot;"/>
      <arg value="&quot;${build.dir}ProjectName.Core.dll&quot;"/>
      <arg value="&quot;${build.dir}Xceed.Compression.dll&quot;"/>
      <arg value="&quot;${build.dir}ProjectName.Infrastructure.dll&quot;"/>
      <arg value="&quot;${build.dir}ProjectName.Infrastructure.XmlSerializers.dll&quot;"/>
    </exec>
    <delete file="${build.dir}ProjectName.Core.dll"/>
    <delete file="${build.dir}Xceed.Compression.dll"/>
    <delete file="${build.dir}ProjectName.Infrastructure.dll"/>
    <delete file="${build.dir}ProjectName.Infrastructure.XmlSerializers.dll"/>
    <move file="${build.dir}\Temp\ProjectName.Infrastructure.dll" tofile="${build.dir}ProjectName.Infrastructure.dll"/>
    <delete dir="${temp.dir}" if="${directory::exists(temp.dir)}"/>
  </target>

To be a little more clear. I can use objects out of the Core library but not the Infrastructure library. Because once it tries to instantiate one of those objects it seems .NET attempts to load the dependency but cannot find it.

Upvotes: 6

Views: 919

Answers (4)

Stephen Cleary
Stephen Cleary

Reputation: 457472

The most recent version of ILMerge has a /closed option which works on the transitive closure of the merged assemblies. It solves this exact problem (see sections 2.6 Closed and 4.1 Input assembly not merged in correctly in the ILMerge.doc user manual).

Note that if your library attempts to dynamically load objects from a named assembly, then it would not work because the merged assembly name is different than the original assembly name. There isn't anything ILMerge can do in this case; you'll have to modify your dependency injection to account for this.

Upvotes: 0

Arsen Mkrtchyan
Arsen Mkrtchyan

Reputation: 50752

As I know that is not possible in Visual Studio, but you can compile every project as a netmodule and then join them together as a DLL. Compile like this:

csc misource1.cs misource2.cs misource3.cs /target:module

and then link together with the al.exe tool, see .netmodule Files as Linker Input and C# Assemblies.

Upvotes: 1

Preet Sangha
Preet Sangha

Reputation: 65555

Use ILMerge. It works out of the box to do this.

Upvotes: 4

Warren
Warren

Reputation:

ILMerge! Almost as good as sliced bread.

http://research.microsoft.com/en-us/people/mbarnett/ilmerge.aspx

Upvotes: 2

Related Questions