c# - MEF plugin calling another plugin with same interface -
i trying make (my first mef) system in plugins can recursive, i.e. main system calls mef plugin standard interface, on own can call (or several) plugin(s), , on.
when testing though, plugin not call underlying plugin, starts processing (creating loop).
any idea how can prevent this?
interface:
public interface iconnector { xdocument run(object servicecredentials, object connectorids, object connectorkeys); }
my main plugin inherits interface, , defines import next (the subplugin has same definition):
[export(typeof(iconnector))] public class connector : iconnector { [import(typeof(iconnector))] private iconnector connector; ....
the called plugin initiated (in run method of main plugin):
public xdocument run(object servicecredentials, object connectorids, object connectorkeys) { string calledconnector = path.combine(assemblydirectory, "subplugin.dll"); assemblycatalog assembycatalog = new assemblycatalog(assembly.loadfrom(calledconnector)); compositioncontainer container = new compositioncontainer(assembycatalog); container.composeparts(this); ....
the container should contain 1 plugin, subplugin.dll. call method 'run' in interface invoke subplugin method:
xdocument = connector.run(servicecredentials, connectorids, connectorkeys);
but, instead of running subplugin code, 'run' method in main plugin activates, keeps activating itself.
when remove [export(typeof(iconnector)] in main plugin, subplugin activated, want main plugin able called in same manner.
being new mef stuck how solve this. appreciated!
you should use contracts , specify intent, otherwise mef go infinite loop or pick connector exposes iconnector itself.
some more info msdn.
for example
[export("container", typeof(iconnector))] public class connector : iconnector { [import("component", typeof(iconnector))] private iconnector connector; ....
update
so after giving thought, here example of metadata based approach, , 1 limits number of expensive catalog operations.
the iconnector
using system.xml.linq; namespace common { public interface iconnector { xdocument run(object servicecredentials, object connectorids, object connectorkeys); void identify(); } }
the metadata attribute connectormetadata
using system; using system.collections.generic; using system.componentmodel.composition; namespace common { [metadataattribute] [attributeusage(attributetargets.class)] public class connectormetadata : exportattribute { public string name { get; private set; } public connectormetadata(string name):base(typeof(iconnector)) { name = name; } public connectormetadata(idictionary<string, object> metadata) : base(typeof (iconnector)) { name = convert.tostring(metadata["name"]); } } }
the lazy singleton pluginscatalog
using system; using system.componentmodel.composition; using system.componentmodel.composition.hosting; using system.io; using system.linq; using system.reflection; using common; namespace common { public class pluginscatalog { [importmany] public lazy<iconnector, connectormetadata>[] connectors; private static readonly lazy<pluginscatalog> lazyinstance = new lazy<pluginscatalog>(() => new pluginscatalog()); private pluginscatalog() { var assemblycatalog = new assemblycatalog(assembly.getexecutingassembly()); var path = path.getdirectoryname(assembly.getexecutingassembly().location) ?? directory.getcurrentdirectory(); var directorycatalog = new directorycatalog(path, "*plugin.dll"); var aggregatecatalog = new aggregatecatalog(assemblycatalog, directorycatalog); var container = new compositioncontainer(aggregatecatalog); container.satisfyimportsonce(this); } public static pluginscatalog instance { { return lazyinstance.value; } } public iconnector getconnector(string name) { var match = connectors.singleordefault(s => s.metadata.name.equals(name)); return match == null ? null : match.value; } } }
the "primary" iconnector
using system; using system.xml.linq; using common; namespace common { [connectormetadata("primary")] public class connector : iconnector { public xdocument run(object servicecredentials, object connectorids, object connectorkeys) { pluginscatalog.instance.getconnector("sub").identify(); return default(xdocument); } public void identify() { console.writeline(gettype().fullname); } } }
the "sub" iconnector
using system; using system.xml.linq; using common; namespace subplugin { [connectormetadata("sub")] public class subconnector:iconnector { public xdocument run(object servicecredentials, object connectorids, object connectorkeys) { return default(xdocument); } public void identify() { console.writeline(gettype().fullname); } } }
and program itself:
namespace somef { class program { static void main(string[] args) { var connector = pluginscatalog.instance.getconnector("primary"); connector.identify(); connector.run(null, null, null); } } }
which prints:
somef.connector subplugin.subconnector
hope helps ... :)
Comments
Post a Comment