1

I'm not sure how to describe this best. But I have a problem understanding the load process of Assemblies.
My application uses plug-ins via Reflection. It works pretty fine and I'm quiet happy with that. Now I've stumbled upon a problem which confuses me and I think I missed something:
In one of my modules, I reference another module. At run time all modules are loaded. There are module ClientManager and the calling module Calculations. ClientManager and Calculations are both loaded. Calculations references ClientManager . When Calculations tries to load a class of ClientManager I get a File Not Found-exception.
Both assemblies are loaded from a bytestream in memory (via Assembly.Load(byte[]).
When Calculations tries to load the class of ClientManager this is how it looks like:

loaded: mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
many more Assemblies...
loaded: ClientManager, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
loaded: Calculations, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Name of Assembly to be loaded: ClientManager, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Requested from: Calculations, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null

So, the Assembly is loaded, yet it gets requested and the request fails. What am I missing? Do I have to load the assembly twice?

I'm grateful for any help.

Greetings,
Skalli

Skalli
  • 2,707
  • 3
  • 27
  • 39
  • should be able to just load the first assembly and as long as the secondary assemblies are in the same location, they should load by themselves. – Dustin Davis Aug 03 '11 at 14:38
  • They are in different directories. Every module has it's own directory. What puzzles me is, that I have to load the assembly, even if it's already loaded in the AppDomain. It's not much of a hassle to load the assembly again, but I don't understand why it's neccesary at this point. – Skalli Aug 03 '11 at 14:50
  • If Plugin1.dll references PluginHelper1.dll then put those two in the same directory, load Plugin1.dll and you should be good to go. – Dustin Davis Aug 03 '11 at 16:21
  • Are sure they are being loaded in the same app domain? You should specify the app domain explicitly. – Dustin Davis Aug 03 '11 at 16:46
  • @DustinDavis: Yes, I'm sure it's the same app domain, I only use one and as you can see, it's loaded there, I checked it. I can try to specify it netherless, but I guess it won't make much of a difference. Also, it wouldn't make much sense for me to put them in the same directory. If I put them in the same directoy, it's still not found. It works when it's in the bin directory of my app, but then it would break the encapsulation. Both plug-ins are loaded via reflection Assembly.Load from a byte array. Is it possible that the second lookup fails because the byte array itself has gone? – Skalli Aug 04 '11 at 07:46
  • Can you make calls to the secondary assembly after you've loaded it? – Dustin Davis Aug 04 '11 at 15:03
  • Yes, after I've loaded it, it works fine. – Skalli Aug 05 '11 at 08:35
  • @DustinDavis: I'm using the workaround AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(loadAssembly); in order to check if the load fails (in the Calculations assembly) and load the assembly again. I can then use all classes defined in the assembly without any trouble. – Skalli Aug 05 '11 at 08:46
  • 1
    This is a weird problem I've never encountered it before. Have you tried using ILMerge to combine the primary and secondary assemblies into a single binary assembly? Just as an experiment, try it and see if you still have the same issues. – Dustin Davis Aug 05 '11 at 14:51
  • Havn't tried that yet. But I'll try it on monday. As I said. That behaviour is not what I'd expect. – Skalli Aug 06 '11 at 12:51
  • When I merge the assemblies with ILMerge there is no error. It's definitive a valid alternative to loading the dll again. It's not that interesting for this problem, but for another. (Update modules which require a previous assembly which is not present on the system anymore. With ILMerge I can work around that problem). – Skalli Aug 10 '11 at 10:19

1 Answers1

3

Your problem looks very similar to this one I've encountered developing a plug in: Where does Visual Studio look for assemblies?.

I think that you should first of all understand where .NET is looking for your assembly and compare it with the one which is already loaded in your AppDomain. This can be done using ProcMon.exe to see where your app is not able to find the assembly and looking at the CodeBase property of the ClientManager that you can find in AppDomain.CurrentDomain.GetAssemblies().

I imagine that these 2 paths will be different, but it's difficult to imagine why your app is looking for assemblies in different places without knowing them.

In the end I solved my problem using the AssemblyResolve event, too, simply looking for my assembly in the currently loaded assemblies and just retutning it (without loading it again).

This is how I did it. I'm not so sure that it is really neat, since it works only because the assembly that was not found was already loaded:

AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);

static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
    foreach (Assembly anAssembly in AppDomain.CurrentDomain.GetAssemblies())
        if (anAssembly.FullName == args.Name)
            return anAssembly;
    return null;
}
Community
  • 1
  • 1
Francesco Baruchelli
  • 7,320
  • 2
  • 32
  • 40
  • Thanks for the reply. Your solution sounds very neat and I'll try it out as soon as I have the time. For now I've settled with ILMerge, even if it has some drawbacks (no edit & continue, different project output than ILMerge output, which is trouble when working with WiX...). May I ask how you returned the loaded assembly? I'll mark your post as answer, even though I couldn't try it yet. I'll update on my progress if I tried it though. – Skalli Sep 13 '11 at 07:47