问题
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
回答1:
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:
- Create a new application project which will be the shell application.
- In the shell application, create the
AppDomain
, enable shadow copying and if you wish, specify the directory where shadow copying will be enabled. - Use AppDomain.ExecuteAssembly to call your current application.
If instead of an application you have a class library you can try the following:
- Create a new class library project.
Add the following interface to the new class library project:
public interface IRemoteLoader { void Load(); void Unload(); }
Add an implementation of this interface to your class library that needs to execute in a new AppDomain. In the
Load
andUnload
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.After you create the new AppDomain, use CreateInstanceAndUnwrap to create an instance of the loader class from step 3.
Use the
Load
andUnload
on the object created from step 4.
This will be enough if you do not fine-grained control and simply starting/stopping is enough.
回答2:
This scenario is closer to the auto update feature in mobile apps. Essentially you want to pick up new assemblies if available on App Start / Restart.
One way to design this might be to have a communication mechanism to signal to your app on start that new assemblies are available (maybe a version.txt file). If yes, then the same version.txt file could point to the new location of the assemblies. Yes - you may end up creating a number of sub folders to point to the correct version, but these could be cleaned up by another process.
you could use a hierarchichal structure like so -
Version\ - Version1.0\ - Version2.0\
This type of design would be closer to a well know paradigm of auto update.
回答3:
Do you have the option of not using a DirectoryCatalog and use AssemblyCatalog to load up all the assemblies in the directory ? You could even go to code plex and copy the same code from the DirectoryCatalog class that reads through the directory and loads up the assemblies.
You would lose the ability to load them on the fly, but as you mentioned that's not really a requirement.
来源:https://stackoverflow.com/questions/12593308/mef-and-shadowcopying-dlls-so-that-i-can-overwrite-them-at-runtime