[ACCEPTED]-Embedding assemblies inside another assembly-assemblies

Accepted answer
Score: 59

ILMerge does merge assemblies, which is 53 nice, but sometimes not quite what you want. For 52 example, when the assembly in question is 51 a strongly-named assembly, and you don't 50 have the key for it, then you cannot do 49 ILMerge without breaking that signature. Which 48 means you have to deploy multiple assemblies.

As 47 an alternative to ilmerge, you can embed 46 one or more assemblies as resources into 45 your exe or DLL. Then, at runtime, when 44 the assemblies are being loaded, you can 43 extract the embedded assembly programmatically, and 42 load and run it. It sounds tricky but there's 41 just a little bit of boilerplate code.

To 40 do it, embed an assembly, just as you would 39 embed any other resource (image, translation 38 file, data, etc). Then, set up an AssemblyResolver 37 that gets called at runtime. It should 36 be set up in the static constructor of the 35 startup class. The code is very simple.

    static NameOfStartupClassHere()
    {
        AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(Resolver);
    }

    static System.Reflection.Assembly Resolver(object sender, ResolveEventArgs args)
    {
        Assembly a1 = Assembly.GetExecutingAssembly();
        Stream s = a1.GetManifestResourceStream(args.Name);
        byte[] block = new byte[s.Length];
        s.Read(block, 0, block.Length);
        Assembly a2 = Assembly.Load(block);
        return a2;
    }

The 34 Name property on the ResolveEventArgs parameter 33 is the name of the assembly to be resolved. This 32 name refers to the resource, not to the 31 filename. If you embed the file named "MyAssembly.dll", and 30 call the embedded resource "Foo", then the 29 name you want here is "Foo". But that would 28 be confusing, so I suggest using the filename 27 of the assembly for the name of the resource. If 26 you have embedded and named your assembly 25 properly, you can just call GetManifestResourceStream() with 24 the assembly name and load the assembly 23 that way. Very simple.

This works with 22 multiple assemblies, just as nicely as with 21 a single embedded assembly.

In a real app 20 you're gonna want better error handling 19 in that routine - like what if there is 18 no stream by the given name? What happens 17 if the Read fails? etc. But that's left 16 for you to do.

In the rest of the application 15 code, you use types from the assembly as 14 normal.

When you build the app, you need 13 to add a reference to the assembly in question, as 12 you would normally. If you use the command-line 11 tools, use the /r option in csc.exe; if 10 you use Visual Studio, you'll need to "Add 9 Reference..." in the popup menu on the project.

At 8 runtime, assembly version-checking and verification 7 works as usual.

The only difference is in 6 distribution. When you deploy or distribute 5 your app, you need not distribute the DLL 4 for the embedded (and referenced) assembly. Just 3 deploy the main assembly; there's no need 2 to distribute the other assemblies because 1 they're embedded into the main DLL or EXE.

Score: 35

Take a look at ILMerge for merging assemblies.

I'm 9 also a little confused about why .NET assemblies 8 are .dll files. Didn't this format exist 7 before .NET?

Yes.

Are all .NET assemblies 6 DLLs,

Either DLLs or EXE normally - but 5 can also be netmodule.

but not all DLLs are 4 .NET assemblies?

Correct.

Why do they use 3 the same file format and/or file extension?

Why 2 should it be any different - it serves the 1 same purpose!

Score: 8

You can embed an assembly (or any file, actually) as 12 a resource (and then use the ResourceManager class to access 11 them), but if you just want to combine assemblies, you're 10 better off using a tool like ILMerge.

EXE and DLL 9 files are Windows portable executables, which are generic enough to 8 accomodate future types of code, including 7 any .NET code (they can also run in DOS 6 but only display a message saying that they're 5 not supposed to run in DOS). They include 4 instructions to fire up the .NET runtime 3 if it isn't already running. It's also possible 2 for a single assembly to span across multiple 1 files, though this is hardly ever the case.

Score: 5

Note ILMerge doesn't work with embedded 2 resources like XAML, so WPF apps etc will 1 need to use Cheeso's method.

Score: 4

There's also the mkbundle utility offered 1 by the Mono project

Score: 1

Why do they use the same file format and/or 7 file extension?

Why should it be any different 6 - it serves the same purpose!

My 2¢ bit of 5 clarification here: DLL is Dynamic Link 4 Library. Both the old style .dll (C-code) and 3 .net style .dll are by definition "dynamic 2 link" libraries. So .dll is a proper description 1 for both.

Score: 0

With respect to Cheeso's answer of embedding 32 the assemblies as resources and loading 31 them dynamically using the Load(byte[]) overload 30 using an AssemblyResolve event handler, you 29 need to modify the resolver to check the 28 AppDomain for an existing instance of the 27 Assembly to load and return the existing 26 assembly instance if it's already loaded.

Assemblies 25 loaded using that overload do not have a 24 context, which can cause the framework to 23 try and reload the assembly multiple times. Without 22 returning an already loaded instance, you 21 can end up with multiple instances of the 20 same assembly code and types that should 19 be equal but won't be, because the framework 18 considers them to be from two different 17 assemblies.

At least one way that multiple 16 AssemblyResolve events will be made for 15 the same assembly loaded into the "No 14 context" is when you have references 13 to types it exposes from multiple assemblies 12 loaded into your AppDomain, as code executes 11 that needs those types resolved.

https://msdn.microsoft.com/en-us/library/dd153782%28v=vs.110%29.aspx

A couple 10 of salient points from the link:

"Other 9 assemblies cannot bind to assemblies that 8 are loaded without context, unless you handle 7 the AppDomain.AssemblyResolve event"

"Loading 6 multiple assemblies with the same identity 5 without context can cause type identity 4 problems similar to those caused by loading 3 assemblies with the same identity into multiple 2 contexts. See Avoid Loading an Assembly 1 into Multiple Contexts."

Score: 0

I would suggest you to try Costura.Fody. Just don't 2 forget to Install-Package Fody before Costura.Fody 1 (in order to get the newest Fody!)

More Related questions