I often get asked how one would ship a single assembly app that is in multiple assemblies...

Well, you have some options.  MS Research has the ILMerge utility, though I've found it doesn't work super great.  I've seen some other tools that claim to do the same thing, but haven't played with them.  I'm going a different approach.  I'm going to show you how you can use a loader assembly in order to compile a single exe that consumes multiple other assemblies as resources.  The initial file layout will be:

QuantumComputer.dll
ShorComputer.exe
DelayRunner.exe

Okay, so the DelayRunner.exe is my new code, while the ShorComputer.exe and QuantumComputer.dll are the files I want merged.  We'll compiled DelayRunner.exe using the following command line (and then I'll jump into the code that I've used).

csc /t:exe /res:ShorComputer.exe /res:QuantumComputer.dll /out:DelayRunner.exe DelayRunner.cs

Okay, time to get to work.  As soon as DelayRunner is loaded, we are going to have to load our two real assemblies and start operating on them.  I'll keep this code simple and it involves hooking our AssemblyResolve event, loading up our first assembly (ShorComputer.exe) into the current appdomain, and finally grabbing and executing it's entry point.

private static void Main(string[] args) {
    resourceAssembly = Assembly.GetEntryAssembly();

    AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(ResolveInternalAssembly);
    Assembly target = AppDomain.CurrentDomain.Load("ShorComputer");
    MethodInfo entryPoint = target.EntryPoint;

    if ( entryPoint != null ) {
        entryPoint.Invoke(null, new object[] { args });
    }
}

Super easy.  All of the real work is going into the ResolveInternalAssembly.  For this method we are going to store a hashtable of dynamic assemblies that we are going to create directly from the resources embedded in our DelayRunner.  We start by grabbing what I call the short name.  You see when we call our event with ShorComputer, that is what our Name property will be in our ResolveEventArgs, aka, we already have a short name.  However, when QuantumComputer gets requested, it'll be based on the full name as specified in ShorComputer's assembly manifest, and we really only want the short name in order to do our custom probing.  I'm pointing this out, because you would need to do additional work here if you had assemblies that differed by say only version or by only public key.  I'm assuming the short name will uniquely identify your assemblies.

string shortName = e.Name.Split(',')[0];

Our next step is to check into our assembly hash table and make sure we haven't already loaded this assembly.  This is important, since there really isn't any caching logic provided when you load assemblies from byte[]'s.  We want to make sure that all requests for the assembly with the same name are given the same Assembly object in return rather than loading a new one.  If it doesn't exist, then we enumerate our resources, find a matching assembly there, and load it.

if ( dynamicAssemblyHash[shortName] == null ) {
    string[] resources = resourceAssembly.GetManifestResourceNames();
    foreach(string name in resources) {
        if ( Path.GetFileNameWithoutExtension(name) == shortName ) {
            using(Stream asmStream = resourceAssembly.GetManifestResourceStream(name)) {
                byte[] exeBytes = new byte[asmStream.Length];
                asmStream.Read(exeBytes, 0, exeBytes.Length);
                asmStream.Close();

                dynamicAssemblyHash[shortName] = Assembly.Load(exeBytes);
            }
        }
    }
}

return dynamicAssemblyHash[shortName] as Assembly;

That's pretty much it.  You now have a single assembly on disk named DelayRunner.exe that is approximately 5K-20K larger than the original assemblies depending on the settings you use to compile everything.  Not bad for quickly generating a single assembly distribution.

Published Monday, June 07, 2004 3:10 AM by Justin Rogers

Comments

Monday, June 07, 2004 12:21 PM by Jerry Dennany

# re: I often get asked how one would ship a single assembly app that is in multiple assemblies...

I did something sorta like this a while back.

http://weblogs.asp.net/jdennany/archive/2003/09/24/29035.aspx

Wednesday, August 20, 2008 10:35 PM by Hardik

# re: I often get asked how one would ship a single assembly app that is in multiple assemblies...

Hey Buddy,

Your article helped me a lot. It has solved my important query. Thanks dear,

Regards,

Hardik.

Leave a Comment

(required) 
(required) 
(optional)
(required)