title: Load, Use and the Unload an Assembly at runtime
body: <p>I am working on a project where I have to load assemblies (lets call them tasks) at runtime, run the task and then be able to kill off the whole assembly so that the dll can be replaced without interrupting the main application.</p>
  
  <p>There are many of these tasks running within the main application, some run sequentially and some run in parallel.   Occasionally one or to of these tasks need to be updated and then re-added to the queue.   Currently we are stopping the entire application and interrupting the other tasks at whatever stage they are at, which is not ideal.</p>
  
  <p>I have figured out that I will have to load each assembly into a separate AppDomain, but loading the assemblies in those domains is proving difficult, especially when I need to actually run the tasks and receive events from them.   I have been looking into this problem for a couple of days and have still not managed to get a working proof-of-concept.</p>
  
  <p>I have an Interface for the tasks which includes a 'run' and 'kill' method (subs) and a 'taskstep', 'complete' and 'killed' event.   'taskstep' returns an object to be cached later, 'complete' fires when the whole task is done and 'killed' fires when it is ready to be unloaded.   There should also be a timeout on the whole process of two hours and a timeout of 2 minutes on the killed event in case it gets stuck, at which point I would like to be able to unload it, forcing any threads to terminate (which is what 'kill' should do anyway).   Each assembly may contain several tasks, all of which should loadable be unloadable.</p>
  
  <p>I have no problems loading these tasks as 'plugins' but am lost when trying to both use them and unload them.   If I have to create some elaborate wrapper then so be it but is what I need even possible?</p>
  
  <p>I have tried inheriting from MarshalByRefObject but I do not even know the assembly fullname unless I load it first, which then locks the file.  I have tried loading from a byte array of the assembly.  This means that the file is not locked but a copy of it remains in the current appdomain.  This will become problematic over the following months / years!</p>
  
  <pre><code>For Each key As String In assemblies.Keys
  
      Dim ad As AppDomain = AppDomainHelper.BuildChildAppDomain(AppDomain.CurrentDomain, key)
  
      AddHandler ad.AssemblyResolve, AddressOf AssemblyResolve
  
      _l.Add(ad)
  
      For Each value As String In assemblies(key)
          Dim item As IScanner = CType(ad.CreateInstanceAndUnwrap(key, value), IScanner)
          ListBox1.Items.Add(item)
      Next
  Next
  
  Private Function AssemblyResolve(sender As Object, args As ResolveEventArgs) As Assembly
      Return GetType(IScanner).Assembly
  End Function
  </code></pre>