Search code examples
c#.netvisual-studioassembliesembedded-resource

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


I have one assembly(MyAssembly.dll)(something like wrapper) which has a few references to other assemblies(3rdAssembly1.dll, 3rdAssembly2.dll). These referenced assemblies are embedded into my assembly as embedded resources. In my assembly I have main class(MyClass) which calls some functions from these third-party assemblies. This class has one default constructor where I try to resolve required dependencies as below:

public MyClass{
  AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(Resolver);
}

public static System.Reflection.Assembly Resolver(object sender, ResolveEventArgs args)
{
    string source = "MyAssembly.Resources."+args.Name.Remove(args.Name.IndexOf(','))+".dll";
    //source = "MyAssembly.Resources.3rdAssembly1.dll"
    //source = "MyAssembly.Resources.3rdAssembly2.dll"

    Assembly a1 = Assembly.GetExecutingAssembly();
    Stream s = a1.GetManifestResourceStream(source);
    byte[] block = new byte[s.Length];
    s.Read(block, 0, block.Length);
    Assembly a2 = Assembly.Load(block);
    return a2;
}

Then I try to use my assembly(MyAssembly.dll) as embedded resource in my host app(MyApp.exe) where I also use Resolver function.

static void main(string[] args){
  AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(MainResolver);

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

static System.Reflection.Assembly MainResolver(object sender, ResolveEventArgs args)
{
    string source = "MyApp.Resources."+args.Name.Remove(args.Name.IndexOf(','))+".dll";
    //source = "MyApp.Resources.MyAssembly.dll"
    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 problem is my host app doesn't resolve internal assemblies(3rdAssembly1.dll, 3rdAssembly2.dll), because Resolver function in MyClass is never called. The host app tries to resolve all of them and as a result fails. I played around with it and found out that if I exclude MyAssembly.dll from embedded resource and locate it in the same folder with host app, and replace += new ResolveEventHandler(MainResolver) on += new ResolveEventHandler(MyClass.Resolver) in main function then it works! It is necessary to have one assembly, because I'm going to use it in several apps and I don't want to include all referenced assemblies in all apps every time.

So, my question is how to resolve all dependencies(MyAssembly.dll and all internal ones which are contained in MyAssembly.dll as embedded resources) in host app?

Thanks in advance!


Solution

  • 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!