MEF - notify when plugins are loaded / unloaded
I have a simple asp mvc app which uses MEF, and there is a route which can be accessed by admins to refresh the directory catalog and compose parts, however one thing I am trying to find out how to do is notify some code when a plugin is loaded / unloaded.
The scenario is that when plugins are loaded they register the routes they need, however when they are unloaded I need them to unlo开发者_开发百科ad their routes, as subsequent refreshes try to re-register the routes and it bombs.
Are there any events which I can hook into from the MEF objects?
The plugin container is something like:
[ImportMany(typeof(ISomePluginInterface))]
IEnumerable<ISomePluginInterface> Plugins {get; private set;}
Each ISomePluginInterface has something like:
public interface ISomePluginInterface
{
public void PluginLoaded();
public void PluginUnloaded();
}
This is similar in theory to this Stackoverflow question and this was my answer. In your case, you have a similar need, you want to fire an event when the plugin is started, and clean up when it is no longer needed.
Using the same concept, you can use the InterceptingCatalog
to register routes, but I wouldn't make it an explicit part of the interface definition to do so, instead, you need to look at how your components fit together as a whole, e.g., if the operations for registering routes won't be used for all plugins, what is the purpose of them existing in the interface definition. You could break out the route registration into a separate interface, the IRouteRegistrar
, and use intercepting strategies to automatically call the appropriate registration method when the plugin is used for the first time, e.g., I could break out the interface into:
public interface IPlugin
{
void SomeOperation();
}
public interface IRouteRegistrar : IDisposable
{
void RegisterRoutes();
}
The latter interface does the work of registering routes, and we use the Dispose
pattern to ensure that it is cleaned up after it is finished with. Therefore, A sample plugin could resemble:
[Export(typeof(IPlugin))]
public class MyPlugin : IPlugin, IRouteRegistrar
{
public void SomeOperation() { }
public void RegisterRoutes()
{
// Register routes here...
}
protected virtual Dispose(bool disposing)
{
if (disposing)
{
// Unregister routes here...
}
}
void IDisposable.Dispose()
{
Dispose(true);
}
}
I only export as an IPlugin
, but I ensure my plugin also implements the IRouteRegistrar
. The way we use that, is with a strategy:
public class RouteRegistrarStrategy : IExportedValueInteceptor
{
public object Intercept(object value)
{
var registrar = value as IRouteRegistrar;
if (registrar != null)
registrar.RegisterRoutes();
return value;
}
}
Now, only if the plugin supports that interface will it register routes. This also enables you to apply the route registration interface to other plugins which could be used in a different way. You gain a bit more flexibility. To use that strategy in code, you need to add the MefContrib project to your app, and do a little more wire up:
var catalog = new DirectoryCatalog(".\bin");
var config = new InterceptionConfiguration().AddInterceptor(new RouteRegistrarStrategy());
var interceptingCatalog = new InterceptingCatalog(catalog, configuration);
var container = new CompositionContainer(interceptingCatalog);
精彩评论