2570

Lazy load a DLL that was placed on the filesystem after the program has been started

Question:

I am building an automation harness using C# and am trying to do the following:

<ul><li>Bootstrap the harness</li> <li>Install the executable</li> <li>Use a couple of DLLs that the executable lays down to establish a connection to the infrastructure that the exe connects to (large, complex software system)</li> </ul>

The DLLs that I need to use are a few static classes that perform their own 'bootstrap' process to get connected to the rest of the servers in the test environment. What I have tried is creating a connection class that looks like this:

using CompanyName.Framework; namespace TestNamespace{ public class ProductConnectorClass{ // Initialize a connection to the product and do stuff public ProductConnectorClass(){ var connection = CompanyName.Framework.Initialize(...); // Do stuff with the connection connection.RunStuff(); } } }

The DLL that contains the <b>CompanyName.Framework</b> namespace is not accessible when the test framework is first started. It is copied via code from another class that looks lomething like this:

namespace TestNamespace{ public class TestRunnerClass{ public TestRunnerClass(){ // pseudo code here, so you get the idea: CopyMsiToHost(msiRemotePath, msiLocalPath); InstallMsi(msiLocalPath); CopyDllsToTestHarnessDir(); ProductConnectorClass pcc = new ProductConnectorClass(); } } }

It is when the code hits the <b>ProductConnectorClass pcc = new ProductConnectorClass();</b> line that I get an exception:

FileNotFoundException was unhandled Could not load file or assembly 'CompanyName.Framework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=XXXXXXXXXXXXXXXX' or one of its dependencies. The system cannot find the file specified.

This puzzles me since I have set <b>Specific Version: False</b> on the DLL in my test project and I am operating under the assumption that .NET Lazy-loads DLLs (in my mind that means search for and load them at the time they are needed). At this point I am looking for a simple way to get a running .NET program to find a needed DLL that has been placed after the process started running.

<b>Note 1:</b> If I restart the process after the DLL is already in place, it loads fine. It looks like it is only scanning for DLLs on startup, which still puzzles me.

<b>Note 2:</b> This <a href="https://stackoverflow.com/a/4483570" rel="nofollow">SO answer</a> gives me some information about how DLLs are loaded, but doesn't fully answer my question. The synopsis is that if .NET has tried to load the DLL and it fails that it won't try to load it again. In my case I don't expect that a load attempt has been made on the DLL since the class where the DLL is referenced has not been instantiated yet.

Answer1:

From experiments in test projects that I have performed, it appears that I need to perform modularization of my code in order to get this to work. In no case am I able to reference a dll that does not currently exist, start my program then drop down the DLL.

Here are my steps to a solution:

<ul><li>Refactor my common classes and interfaces to their own DLL project in my Automation solution</li> <li>Create another DLL project ('TestLogic') in my solution that uses the DLL I lay down after the program has started</li> <li>When I need to use the DLL that is laid down after the program starts, I use reflection to load the TestLogic dll and perform the tests</li> </ul>

For reference I did a google search for 'C# late load dll' and found <a href="http://social.msdn.microsoft.com/Forums/vstudio/en-US/8508148b-9d30-4d7b-b5b4-20af94d28c21/how-do-i-late-bind-reference-dll" rel="nofollow">this msdn social post</a> with some helpful advice. Here is a copy/paste/modify of the most helpful reply from that thread:

<ol><li>Move all the code that references the DLLs that are installed after the test framework starts to a completely separate assembly. We'll call this "TestLogicAssembly".</li> <li>Create a new assembly and define an interface. We'll call this "TestInterfaceAssembly".</li> <li>Reference TestInterfaceAssembly in both your main DLL and your TestLogicAssembly.</li> <li>Create a class in TestLogicAssembly that implements the interface created in TestInterfaceAssembly.</li> <li>Don't reference TestLogicAssembly from your main application.</li> <li>At runtime, check to see if the DLLs that are laid down as part of the install step of the test framework are actually installed. If they are, use Assembly.Load to load the TestLogicAssembly, then find the type that implements the interface defined in number 2. Use Activator.CreateInstance to create an instance of this type, and cast it to the interface you created. </li> </ol>

Recommend

  • Unix awk scripting to convert columns to rows
  • Reduce left joins complexity
  • How to exclude some of the folders while creating zip file through maven
  • App-store submission [closed]
  • RTL (Right-to-left) via auto layout broken on iOS 6.1 / iOS 7.0?
  • 401 IIS Error for SearchAdmin.asmx
  • VC++ missing type specifier - int assumed. Note: C++ does not support default-int [duplicate]
  • Android doesn't show logcat messages
  • Spring Boot exception: java.lang.NoSuchMethodError: StandardJarScanner.setJarScanFilter(Lorg/apache/
  • Failure to update Laravel 5.1 to 5.2 (these conflict with your requirements or minimum-stability)
  • XML request in PHP NuSoap - “HTTP/1.1 400 Bad Request”
  • Azure Bot Framework Emulator Error - System.ArgumentNullException: Value cannot be null
  • Cabal getting installed in root directory instead of /home/vagrant directory using Vagrantfile
  • Contact Usage permission request iphone
  • Internet Explorer 10 back button caching
  • Identifying the browser at server side in php
  • nested json objects dont update / inherit using Json.NET
  • HTML file fetched using 'wget' reported as binary by 'less'
  • Add vertical separator and labels to R barplot
  • Hadoop/map-reduce: Total time spent by all maps in occupied slots vs. Total time spent by all map ta
  • Easy Way to Get Averages Based on Names in List
  • if(!isset($_POST[“user”]) ignored and returns Undefined Index
  • Custom WebViewPage inject code when razor template is rendering
  • Rest Services conventions
  • Elasticsearch script query involving root and nested values
  • FB SDK and cURL: Unknown SSL protocol error in connection to graph.facebook.com:443
  • Using $this when not in object context
  • How do I fake an specific browser client when using Java's Net library?
  • How reduce the height of an mschart by breaking up the y-axis
  • How to convert from System.Drawing.Color to Excel.ColorFormat in C#? Change comment color
  • javascript inside java/jsp code
  • Perl system calls when running as another user using sudo
  • Deserializing XML into class C#
  • Android Studio and gradle
  • How to include full .NET prerequisite for Wix Burn installer
  • IndexOutOfRangeException on multidimensional array despite using GetLength check
  • How to get NHibernate ISession to cache entity not retrieved by primary key
  • costura.fody for a dll that references another dll
  • How can i traverse a binary tree from right to left in java?
  • jQuery Masonry / Isotope and fluid images: Momentary overlap on window resize