This was inspired by this question on StackOverflow. First off, this is bad design unless you are designing some sort of setup application. But, specifically for those who still wish to proceed, here is how you do it.
Download Example Code
EmbeddedReferenceApplication.zip
In this example, there are two projects. 'EmbeddedReferenceApplication.exe' and 'EmbeddedReference.dll'. Here are the steps.
- Add a hard reference to EmbeddedReference.dll from EmbeddedReferenceApplication.exe
- Go to the reference Properties, and set Copy Local = False
- Right click your project and add the referenced assembly as a link (Add As Link)
- Right click the linked assembly in your project, and set its build output to 'Embedded Resource'
- Modify your code with proper manifest name handling/resolution
- See the example code or post comments for more help
using System; using System.Collections.Generic; using System.Text; using System.IO; using System.Windows.Forms; using System.Reflection; using EmbeddedReference; namespace EmbeddedReferenceApplication { class Program { static void Main(string[] args) { AppDomain.CurrentDomain.AssemblyResolve += AppDomain_AssemblyResolve; MyMain(); } private static void MyMain() { EmbeddedReference.MessageHelper.ShowMessage(); } private static Assembly AppDomain_AssemblyResolve(object sender, ResolveEventArgs args) { string manifestResourceName = "EmbeddedReferenceApplication.EmbeddedReference.dll"; // You can also do Assembly.GetExecutingAssembly().GetManifestResourceNames(); string path = Path.Combine(Application.StartupPath, manifestResourceName.Replace("EmbeddedReferenceApplication.", "")); ExtractEmbeddedAssembly(manifestResourceName, path); Assembly resolvedAssembly = Assembly.LoadFile(path); return resolvedAssembly; } private static void ExtractEmbeddedAssembly(string manifestResourceName, string path) { Assembly assembly = Assembly.GetExecutingAssembly(); using (Stream stream = assembly.GetManifestResourceStream(manifestResourceName)) { byte[] buffer = new byte[stream.Length]; stream.Read(buffer, 0, buffer.Length); using (FileStream fstream = new FileStream(path, FileMode.Create)) { fstream.Write(buffer, 0, buffer.Length); } } } } }
What this does is subscribes to AssemblyResolve and allows the application domain to resolve your assembly to a custom path - in our case, we resolve to the application directory but we are extracting the assembly first, and returning the resolved assembly. You can use this same code to resolve dependencies and assemblies from custom directories and paths.
A key note is lines 12 and 13. You must not use any code directly in the Main method that would otherwise reference a dependency. What this causes is for your exception to be thrown while Main is compiled, and before it is run. You will never give the application domain a chance to perform dependency resolution. However, a quick fix is to throw it into a helper method called MyMain (call it SubMain or something similar), that would not otherwise reference the dependency until its invoked.