Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MEF and ShadowCopying DLLs so that I can overwrite them at runtime

I am trying to stop my application locking DLLs in my MEF plugin directory so that I can overwrite the assemblies at runtime (note I'm not actually trying to have MEF reload them on the fly, at the next app start is fine, i just dont want to have to stop the app to do the copy)

I am trying to do this by creating a shadow copied app domain for my mef loaded assemblies as below:

[Serializable]
    public class Composer:IComposer
    {
        private readonly string _pluginPath;
        public Composer(IConfigurePluginDirectory pluginDirectoryConfig)
        {
            _pluginPath = pluginDirectoryConfig.Path;
            var setup = new AppDomainSetup();
            setup.ShadowCopyFiles = "true"; // really??? is bool not good enough for you?
            var appDomain = AppDomain.CreateDomain(AppDomain.CurrentDomain.FriendlyName + "_PluginDomain", AppDomain.CurrentDomain.Evidence, setup);

            appDomain.DoCallBack(new CrossAppDomainDelegate(DoWorkInShadowCopiedDomain));      
        }

        private void DoWorkInShadowCopiedDomain()
        {
            // This work will happen in the shadow copied AppDomain.

            var catalog = new AggregateCatalog();
            var dc = new DirectoryCatalog(_pluginPath);
            catalog.Catalogs.Add(dc);
            Container = new CompositionContainer(catalog);
        }

        public CompositionContainer Container { get; private set; }
    }

and then access my MEF component catalog via the CompositionContainer on this class. However the composition container seems to only be initialised inside the shadowcopy domain (which makes sense) and this means that its null in my application domain. I was just wondering if theres a better way to do this or some way to cross domain query to get my MEF components

like image 417
Not loved Avatar asked Sep 26 '12 01:09

Not loved


1 Answers

If you don't want to follow the solution from Dan Bryant and zync, you could create a shell application that simply executes your application in a new AppDomain.

An approach would be:

  1. Create a new application project which will be the shell application.
  2. In the shell application, create the AppDomain, enable shadow copying and if you wish, specify the directory where shadow copying will be enabled.
  3. Use AppDomain.ExecuteAssembly to call your current application.

If instead of an application you have a class library you can try the following:

  1. Create a new class library project.
  2. Add the following interface to the new class library project:

    public interface IRemoteLoader  
    {  
        void Load();  
        void Unload();  
    }
    
  3. Add an implementation of this interface to your class library that needs to execute in a new AppDomain. In the Load and Unload methods you should add code to perform initialization and cleanup respectively. Make the class derive from MarshalByRefObject. This is needed for .NET Remoting to create proxy objects on both AppDomains.

  4. After you create the new AppDomain, use CreateInstanceAndUnwrap to create an instance of the loader class from step 3.

  5. Use the Load and Unload on the object created from step 4.

This will be enough if you do not fine-grained control and simply starting/stopping is enough.

like image 79
Panos Rontogiannis Avatar answered Nov 01 '22 13:11

Panos Rontogiannis