views:

2035

answers:

2

Actually i tried to implement some kind of 'statically linked' assemblies, within my solution. So i tried the following:

  • Adding a reference to my assembly with CopyLocal = false
  • Adding the .dll file itself to my solution with 'Add as link'
  • Adding the .dll file itself to my resources with 'Add Resource' - 'Add Existing File'
  • Adding some type out of my assembly into Form1 as private MyObject temp = new MyObject();

After these steps i got the FileNotFoundException as expected. So let's try to load the assembly within the AssemblyResolveEvent with this quick hack

AppDomain.CurrentDomain.AssemblyResolve += (sender, e) =>
    {
        Assembly MyAssembly = AppDomain.CurrentDomain.Load(Properties.Resources.ExternalAssembly);
        return MyAssembly;
    };

So this works! I'm able to load my assembly from a resource file within a AssemblyResolveEvent. But this event only happens, if it couldn't find my assembly anywhere else. But how can i get my assembly be loaded before .Net tries to search the different places??

Due to the facts from Checking for Previously Referenced Assemblies i thought it would be possible to load the assembly beforehand into the domain and this would be taken.

I tried this within program.cs by using the following Main() method

static void Main()
{
    LoadMyAssemblies();
    AppDomain.CurrentDomain.AssemblyResolve += (sender, e) => LoadMyAssemblies();
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.Run(new Form1());
}

private static Assembly LoadMyAssemblies()
{
    Assembly result = AppDomain.CurrentDomain.Load(Properties.Resources.MyStaticAssembly);
    return result;
}

But it still runs into the ResolveEventHandler. And far more better, if i load the assembly again and take a look into AppDomain.CurrentDomain.GetAssemblies() i can see that my assembly is loaded twice!!

So any idea why my loaded assembly won't be taken into account when it is loaded before the AssemblyResolve event?? With help of the debugger i also returned a null when the call came from AssemblyResolve, but in this case i got a FileNotFoundException as at the beginning.

+1  A: 

Just in case you didn't know, there is a tool called ILMerge from MS Research that merges assemblies into one file.

Also you can create Multi-file assemblies using the Assembly Linker tool.

Plus to answer you original question, the problem I think is that the runtime does not know that the assembly you loaded manually is the one it should be looking for. So in the assembly resolve event instead of loading the assembly again, just pass back the reference to the assembly that you've manually loaded.

Sijin
ILMerge will be already used in some other situations, but for this case it is not the 'best' solution. Giving in AssemblyResolve the same assembly back is also not a good solution, because if the same assembly also lies in program folder or GAC this one will be taken and the event won't be thrown.
Oliver
+3  A: 

The CLR Binder doesn't know that LoadMyAssemblies() does the same thing as the AssemblyResolve event, and that they are both trying to look for the same assembly and load it.

AssemblyResolve event always gets fired at the point at which the Binder decides that it has searched all possible locations (that are searchable wrt that application) and could not find a match.

This begs the original question, which is, why would you want to statically link your managed assemblies? Read this thread for a lot of discussion on this http://stackoverflow.com/questions/312406/static-linking-advantages

I'll go ahead and answer the part on how to avoid hitting the AssemblyResolve event 1) Put the assembly into the GAC. As far as the Binder is concerned, the GAC always wins. 2) Place your assembly in the probing path and make sure that the Binder picks it up (look for the article 'How the runtime locates assemblies' on MSDN for more on this).

You're right, that the CLR Binder doesn't know anything about my function. But as you already mentioned it will fire the AssemblyResolve event when it has searched all possible locations. But that's not true! It just didn't looked into the list of loaded assemblies within the current AppDomain! But after reading this (http://msdn.microsoft.com/en-us/library/aa98tba8.aspx) it should look there.
Oliver