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
How to Use Class Fields with System.Text.JSON.JSONserializer
Does .Net Provide an Easy Way Convert Bytes to Kb, Mb, Gb, etc.
Entitytype Has No Key Defined Error
Enter "&" Symbol into a Text Label in Windows Forms
Custom Collection Initializers
Visual Studio "Could Not Copy" .... During Build
Getting the Folder Name from a Full Filename Path
C# Selenium 'Expectedconditions Is Obsolete'
Deserialize JSON Array Stream One Item at a Time
What Does Placing a @ in Front of a C# Variable Name Do
Properly Draw Text Using Graphicspath
Readonlycollection or Ienumerable for Exposing Member Collections
Why Is Httpcontext.Current Null After Await
ASP.NET MVC Ambiguous Action Methods