Approach
I am employing MEF to create a plugin-nable, if you will, application. My MEF host has an ILogger which exposes TraceMessage(string message). Class Logger implements ILogger and is decorated with an Export attribute so Logger looks like:
[Export(typeof (ILogger))]
public class Logger : ILogger
{ }
The idea being that the various plugins can be offered a central logger that they can write to. Thus, instantiation would be via [Import] attribue, for example:
[Export(typeof (ILogger))]
public class Logger : ILogger
{
private readonly IWindsorContainer _container;
public ICloudTrace CloudTrace
{
get { return _container.Resolve<ICloudTrace>(); }
}
public Logger()
{
_container = new WindsorContainer(new XmlInterpreter());
}
public void TraceMessage(string categoryName, string componentName, string message)
{
CloudTrace.TraceMessage(categoryName, componentName, message);
}
}
And subsequently a log message would be written via Logger.TraceMessage(string message).
Problem
However, this approach throws an InvalidOperationException in my host when its trying to resolve exports, with an error message Sequence contains no matching element.
Exports are resolved in ResolveType(string commandType) (where commandType is the command line parameter needed to execute relevant plugin). ResolveType() looks like:
public dynamic ResolveType(string commandType)
{
try
{
return this.Container.GetExports<ICommand, ICommandMetaData>()
.First(contract => contract.Metadata.CommandType.Equals(commandType, StringComparison.OrdinalIgnoreCase))
.Value;
}
catch (Exception e)
{
Console.WriteLine(e.message);
}
}
I should mention that each plugin has an Execute(Dictionary<string, string> parameters) which is the entry point for the plugin and the class containing this method is decorated with [Export(typeof(ICommand))] [ExportMetadata("CommandType","CommandLine Command string goes here")] attributes.
The problem was in the
CompositionContainerconstruction. Currently, it just loads the plugin assembly specified in the command line instead of doing directory scan or loading currently executing assembly. This has been done for various reasons. So:where
assemblyToLoadis a string to the .dll file for the specific plugin. However, the logger is in the host so the host’s assembly needs to be loaded. Thus:fixes the issue.
Thanks to @Matthew Abbott for pointing this out