13

I have a C# application program, let's call it App.exe. It references a DLL named A.dll which in turn references another DLL, namely, B.dll. However the way in which they are referenced is a bit different. In the code of A.dll, it has directly referenced B.dll (by going to Project > References > Add B.dll). However my App.exe has code to load A.dll at runtime using Assembly.Load() etc.

So to recap,

App.exe ---- (runtime loading) ---> A.dll ---- (direct reference) ---> B.dll

All three things (App.exe, A.dll and B.dll) reside in the same directory, let's say ExeDir. Now what I want to do is, put A.dll and B.dll in a sub directory of ExeDir. I can do this by using an App.config file that specify the path of A.dll and asking the App.exe to load A.dll from that path. So far so good.

However the problem is that when I do this, .NET gives me an error saying that it cannot find B.dll which is in the same directory as A.dll. If I move it back to the original directory (the same directory as App.exe) then it works fine. Which means, I can put A.dll in a sub directory, but the B.dll needs to be in the original directory.

Is there any way in which I can keep both DLLs in the sub directory?

Sach
  • 10,091
  • 8
  • 47
  • 84

3 Answers3

12

Add a <probing> element in your app.config:

http://msdn.microsoft.com/en-us/library/823z9h8w.aspx

<configuration>
   <runtime>
      <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
         <probing privatePath="bin;bin2\subbin;bin3"/>
      </assemblyBinding>
   </runtime>
</configuration>
Jeff Mercado
  • 129,526
  • 32
  • 251
  • 272
D Stanley
  • 149,601
  • 11
  • 178
  • 240
  • Thanks for the reply D Stanley. But I'm at a bit of a loss here. Can you please tell me what exactly am I supposed to do here? Just to specify this element with the assembly path? – Sach Jan 23 '12 at 06:49
  • 1
    Yes relative to your EXE. For example, in the MSDN example the binder will search in the `BIN` folder by default, but will also search the `bin2` folder, the `bin2\subbin` folder, and the `bin3` folder. Replace `bin;bin2\subbin;bin3` with the folder (relative to the EXE) that A.dll and B.dll are in. Note that you no longer have to specify the path to A.dll if it is included in the probing path. – D Stanley Jan 23 '12 at 14:12
  • Thanks Stanley, I got it to work! It was my fault though, that I didn't explain my complete problem here. The reason why I wanted the DLLs in separate folders is I might have several different A.dlls (content different), and each of them may reference B.dlls. So I wanted to implement safer code, such that if different A.dll wanted to refer to B.dll which also could be vary inside. But looks like it can't be done. Still, thanks! You answered my original question. – Sach Jan 24 '12 at 01:37
9

You can manually resolve the B.DLL assembly by providing an event handler to the AppDomain.AssemblyResolve event of the current AppDomain.

currentDomain.AssemblyResolve += ResolveLostAssemblies;

Then provide an implementation of ResolveEventHandler:

private Assembly ResolveLostAssemblies(object sender, ResolveEventArgs args)
{
    // Find the assembly referenced by args.Name, load it dynamically, and return it.
}

I've found that this provides the most control over which assemblies get loaded and when. It especially works well in the situation where you're application is pluggable and each plugin lives in their own subdirectory of a "plugins" folder (which isn't necessarily the application directory). Technically the assembly doesn't even have to be a physical file using this method. Though D Stanley's method is generally considered more standard.

M.Babcock
  • 18,753
  • 6
  • 54
  • 84
1

One option is to try registering your assemblies in the Global Assembly Cache. http://msdn.microsoft.com/en-us/library/4a9t8a9a.aspx But it's probably not preferable to D Stanley's answer.

LesterDove
  • 3,014
  • 1
  • 23
  • 24