title: C# Windows Service - Cannot load external Class Library from Relative Path
body: <p>I have a windows service that is being passed a fully qualified method name.  It then uses this name to look up the appropriate method in whatever external DLL it happens to be in.  My service has a reference to this DLL and everything seems to work correctly when I reference and load the DLL in a hard coded manner as such:</p>
  
  <pre><code>var DLL = Assembly.LoadFile(@"C:\Users\ishiim\Desktop\TFS\IRSystem\Technical Utilities\Monitoring\TestModules\PingerTests\PingerTests\bin\Debug\PingerTests.dll");
  Type type = DLL.GetExportedTypes()[0];
  </code></pre>
  
  <p>However, I will not know the exact location of these DLLs ahead of time, and of course in this example I'm loading the dll that is produced in the solution's directory, something that won't be there for the service when it's installed.</p>
  
  <p>What I am looking to do is simply load the dll by assembly name from the directory the service is currently running in - and indeed in my bin/debug folder the dll is there.  But when I attempt to load it from the local directory using the fully qualified assembly name, the type returns null:</p>
  
  <pre><code>// Example type TestModuleNamespace.TestModuleClassName
  // Example assembly name TestModuleClassName (They are the same in my case)
  Type type = Type.GetType(typeName + ", " + assemblyName);
  </code></pre>
  
  <p>I should mention that in the preceeding code snippet - the code worked fine when the Class Library was in the same solution as my service, but now that I have separated the two, this method will no longer work, and the type returns null.</p>
  
  <p>I have even attempted to load the DLL(s) using code that uses the current execution directory (allegedly C:\Windows\System32 even though the service exe is NOT there) and this has had no success either:</p>
  
  <pre><code>Assembly serviceAssembly = Assembly.LoadFrom(Path.Combine(Environment.CurrentDirectory, assemblyName + ".dll"));
  AssemblyName[] referencedAssemblies = serviceAssembly.GetReferencedAssemblies();
  List&lt;Assembly&gt; assemblyLst = AppDomain.CurrentDomain.GetAssemblies().ToList();
  foreach (AssemblyName name in referencedAssemblies)
  {
      Assembly.Load(name);
  }
  </code></pre>
  
  <p>There have been many answers on SO about this but I have not been able to understand them as I am new to C# and .NET in general.  My biggest point of confusion is simply this - if an external DLL is referenced in my service, and if that DLL is then copied into the bin directory with that service, then when the service is installed, why must the DLL be "loaded" and why can't it find it in its current "path" if it's supposedly in the same directory?</p>
  
  <p>This feels harder than it should be and that is most likely due to my lack of understanding about how assemblies are loaded at runtime. (libraries, DLLS, these words seem to be used interchangeably for some reason - what is the real term?)</p>
  
  <p>EDIT ------------------------------------------------</p>
  
  <p>I feel like I've caused some confusion over what I am trying to do.  My program does the following:</p>
  
  <p>1-Takes a list of tasks that contain a fully qualified method name
  2-Calls the method, via reflection, in whatever DLL it resides in and returns the value</p>
  
  <p>These DLLs and their method names are not known to my program.  They are passed in.  I can reference these libraries at compile time, as other developers will be writing them, but as to when they are called, and what methods will be called, are completely unknown before hand to my service.</p>
  
  <p>It seems like I have two options:
  1-Make a reference to each DLL I am given that may potentially get called and get the type by using the fully qualified assembly name for a call by reflection
  2-Place all the DLLs in a known location and load them by their exact path location on the filesystem and call them by reflection.</p>
  
  <p>Solution 1 was working <em>when the dll was developed and compiled in the same solution as my service</em>.  The second I moved the dll into its own solution, this code <code>Type type = Type.GetType(typeName + ", " + assemblyName);</code> started returning a null.</p>
  
  <p>Solution 2 is also fine, however I cannot seem to call the assemblies with a relative path.  I'd have to store the current path of the executing assembly (my service) and then append that to the target assembly name to get the type and then use reflection to invoke the method.  This way seems very ugly to me but so be it.</p>
  
  <p>EDIT ONCE MORE ---</p>
  
  <p>This is what I ended up doing.  I absolutely hate this, I don't understand why I have to LOAD THE ASSEMBLY AGAIN if I've already made a reference but this works:</p>
  
  <pre><code>String path = System.Reflection.Assembly.GetExecutingAssembly().Location;
  testModuleLocation = System.IO.Path.GetDirectoryName(path);
  Assembly asm = Assembly.LoadFile(System.IO.Path.Combine(testModuleLocation, assemblyName + DLL_FILE_EXT));
  Type type = asm.GetExportedTypes()[0];
  object instance = Activator.CreateInstance(type);
  MethodInfo method = type.GetMethod(methodName);
  method.Invoke(instance, arguments);
  </code></pre>
  
  <p>The "TestModuleLocation" being some sub-folder of my service that I will have to dump all the DLLs into when I build and then install the service.</p>
  
  <p>I think there is a lot about a "DLL" that isn't simply a library and in no way works as it does in any other language I've used.  I guess I have a lot of research to do to re-learn how a library works on windows machines.</p>