Embedding Assemblies Inside Another Assembly

Embedding assemblies inside another assembly

Take a look at ILMerge for merging assemblies.

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

Yes.

Are all .NET assemblies DLLs,

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

but not all DLLs are .NET assemblies?

Correct.

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

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

put together all assemblies and use it as embedded resource in exe

I solved this issue. When the host app runs and doesn't find required assembly, it calls AssemblyResolve event. So, I have to use event handler called MainResolver to load MyAssembly.dll. Then before using methods of MyAssembly.dll, it's necessary to remove it from AssemblyResolve, because the app tries to resolve dependencies using ResolveEventHandler in order which they were added (It calls MainResolver and then Resolver). As a result the host app fails, because it can't find required assemblies in MainResolver. The solution is to reorder ResolveEventHandler or remove MainResolver from AssemblyResolve after it was called. I think that exclude useless handler is easier.

So, I don't need to change anything in MyClass. Everything I need is to add following code in host app before I create instance of MyClass.

static MyApp(){
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(MainResolver);
}

static void main(string[] args){
//remove MainResolver
AppDomain.CurrentDomain.AssemblyResolve -= MainResolver;

MyClass my = new MyClass();
my.DoWork();
}

Now it works like a charm!

Automatically Embed Referenced Assemblies

For a few months, I was building the solution, copying DLLs into an EmbeddedAssemblies folder and then rebuilding the project. It was really painful because I had to write a .bat file that would call MSBuild on my entire .sln, then do an XCOPY and then call MSBuild on the .csproj.

Worse, because I have no control over how TFS ignores files, source control was constantly seeing these files as changing and I had to explicitly Exclude them from check-ins. My teammates were usually not so considerate.

Ultimate, I took another look at ILMerge. Internally, it is pretty much doing the exact same thing I was. I switched over to ILMerge and I've been happier ever since.

Embedding one dll inside another as an embedded resource and then calling it from my code

Once you've embedded the third-party assembly as a resource, add code to subscribe to the AppDomain.AssemblyResolve event of the current domain during application start-up. This event fires whenever the Fusion sub-system of the CLR fails to locate an assembly according to the probing (policies) in effect. In the event handler for AppDomain.AssemblyResolve, load the resource using Assembly.GetManifestResourceStream and feed its content as a byte array into the corresponding Assembly.Load overload. Below is how one such implementation could look like in C#:

AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
var resName = args.Name + ".dll";
var thisAssembly = Assembly.GetExecutingAssembly();
using (var input = thisAssembly.GetManifestResourceStream(resName))
{
return input != null
? Assembly.Load(StreamToBytes(input))
: null;
}
};

where StreamToBytes could be defined as:

static byte[] StreamToBytes(Stream input) 
{
var capacity = input.CanSeek ? (int) input.Length : 0;
using (var output = new MemoryStream(capacity))
{
int readLength;
var buffer = new byte[4096];

do
{
readLength = input.Read(buffer, 0, buffer.Length);
output.Write(buffer, 0, readLength);
}
while (readLength != 0);

return output.ToArray();
}
}

Finally, as a few have already mentioned, ILMerge may be another option to consider, albeit somewhat more involved.

Find all embedded resources in another assembly

You should use GetManifestResourceNames method from Assembly class (msdn):

string[] resourceNames = this.GetType().Assembly.GetManifestResourceNames();
foreach(string resourceName in resourceNames)
{
Console.WriteLine(resourceName);
}

Embedding C# class libraries into an assembly and loading them dynamically

I found a satisfying solution, so here it is if anybody else hits the wall.

If you are compiling code dynamically - code that requires referenced class libraries which in turn are supposed to be embedded as resources into your assembly, make sure to disable GenerateInMemory and to NOT execute the file immediately via Invoking.

If you want (like me) to compile an assembly then execute it immediately, generate it to a file, create an AppDomain and execute it inside of it as seen here:

var assembly = Compiler.Create(files, references, resources, "TestAssembly.TestEntryPoint");

var domain = AppDomain.CreateDomain("ScriptDOM");

domain.ExecuteAssembly(assembly.Location);

Here's the compiler params:

var parameters = new CompilerParameters();
parameters.ReferencedAssemblies.AddRange(references);
parameters.EmbeddedResources.AddRange(resources);
parameters.GenerateExecutable = true;
parameters.GenerateInMemory = false;
parameters.IncludeDebugInformation = true;
parameters.CompilerOptions = "/optimize";
parameters.MainClass = entryPoint;

How do you load embedded assemblies that you've bundled in with your main assembly?

There's an Assembly.Load(byte[]) overload that you can use to load assemblies from an in memory array. If I remember correctly, that's the way LINQPad works for instance. Here's a way to do it, given assembly being an instance of System.Reflection.Assembly, containing other assemblies as managed resources:

Stream embedded = assembly.GetManifestResourceStream ("asm.dll");
byte [] buffer = new byte [embedded.Length];
using (embedded) {
int length = buffer.Length;
int offset = 0;
while (length > 0) {
int read = assemblyStream.Read (buffer, offset, length);
if (read == 0)
break;

length -= read;
offset += read;
}
}

Assembly assembly = Assembly.Load (buffer);

The issue with this one is that the runtime have to pin the byte array, so I'd suggest writing the assembly to a temporary file and use Assembly.LoadFile.

Both methods return a System.Reflection.Assembly object, that you can use to get types and then do whatever you want with them.

How can I embed C# assembly resources in the same assembly?

To murge multiple assemblys into one you can use Fody/Costura.
It allows you to merge multiple assemblys into 1 project.
In your main project you add it(can be done via nuget).
Then just in weavers.xml (file that will be automaticly generated add these text:

<Costura>
<IncludeAssemblies>
Project.MyData.Dutch
Project.MyData.French
Project.MyData.English
</IncludeAssemblies>
</Costura>

(it should be the same name as the reference, so without the .dll suffix)

Embedding .dlls - Assembly resolving in C#

You need to put the code in your main entry point. Something like this:

class Program
{
static Program()
{
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
}

static void Main(string[] args)
{
// what was here is the same
}

static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
// the rest of sample code
}

}

You can't just add an App.xaml file to a windows forms application.

Also that sample code for CurrentDomain_AssemblyResolve is bizarre, I would try this code first. I haven't tested it but it looks more like the code I've used before.



Related Topics



Leave a reply



Submit