dotnet / ILMerge

ILMerge is a static linker for .NET Assemblies.
MIT License
1.22k stars 169 forks source link

Fail to load plugin in Console application merged with ILMerge #58

Closed moh-hassan closed 5 years ago

moh-hassan commented 5 years ago

I merged a Console application that reference a class libray mylib.dll in net45 with ILMerge utility.

The Console application load plugin(s) at runtime that implement an Interface.

The plugin reference the same class library mylib.dll that is used by console.exe

If I run the console application without merge, it can load the plugin successfully.

The merge command

ilmerge /out:"outdir\console.exe" console.exe *.dll 
    /target:exe /targetplatform:v4,C:\Windows\Microsoft.NET\Framework\v4.0.30319 /wildcards /ndebug 

But When merging the console application with all its dependencies using ILMerge, the plugin can't be loaded and raise an exception:

Loader Exception: System.IO.FileNotFoundException: Could not load file or assembly 'mylib.dll, Version=3.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified. File name: 'mylib.dll, Version=3.0.0.0, Culture=neutral, PublicKeyToken=null'

The question: As the assemply mylib.dll is merged in exe, is there a way to extract that assemply at runtime and load it using the event AppDomain.CurrentDomain.AssemblyResolve

mike-barnett commented 5 years ago

Sorry, but that won't work. ILMerge works by taking each member of the input assemblies and reparents them so that they belong to the merged assembly. For instance, if there is a type T in an assembly A, then it's fully-qualified name is "[A]T" (using the format that you'll see if you use ildasm to open an assembly). If you use ILMerge to merge assembly A into the merged assembly M, then the type T has the fully-qualified name "[M]T". It is a totally distinct type (to .NET) from [A]T.

Hope that is clear. Let me know if you need any more help.

moh-hassan commented 5 years ago

Thanks for reply. Is there other way to resolve the plugin problem?

mike-barnett commented 5 years ago

Sorry, not that I am aware of. The assembly you are trying to load at runtime was compiled against "mylib" and so that assembly must be present in order to load/run the assembly.

moh-hassan commented 5 years ago

Kindly, mylib is merged in the exe,

So, should i exclude that library for merging? Do I move the types/interfaces used by the plugin in a separate library and exclude it from merging.? Is there something can control the feasibility of some types like you do in internalize option? may be future feature.

mike-barnett commented 5 years ago

Well, yes, if you don't merge mylib.dll into the merged assembly then your console application will still have a dependence on it. So to run your application mylib.dll will have to be found by the .NET Runtime and so will be available when the plugin executes and also needs it. I don't see any feature that will ever make your scenario work: you would have to re-compile the plugin so that it references the merged assembly instead of mylib.dll.

moh-hassan commented 5 years ago

Thanks @mike-barnett. I will take into account this constraint for using external plugin(s).

lobster2012-user commented 5 years ago

Hi to all. https://github.com/lobster2012-user/Lobster.Home.DependencyInjection.ServiceTypeProvider/tree/master/ILMerge.AutoResolveMergedAssemblies

Here is an example implementation, you need to prescribe with the list of libraries with your hands. Ideally, ILMerge does it all by itself.

[assembly: AutoResolveMergedAssembliesAttribute("ILMergeDynamic.BaseModule")]
  [assembly: AutoResolveMergedAssembliesAttribute("Lobster.Home.DependencyInjection.ServiceTypeProvider")]
MainAssembly.Main()
{ 
   AutoResolverInstaller.EnsureInstalled()
}