I have a following code:
public class Temp<T, TMetadata>
{
[ImportMany]
private IEnumerable<Lazy<T, TMetadata>> plugins;
public Temp(string path)
{
AggregateCatalog aggregateCatalog = new AggregateCatalog();
aggregateCatalog.Catalogs.Add(new DirectoryCatalog(path));
CompositionContainer container = new CompositionContainer(aggregateCatalog);
container.ComposeParts(this);
}
public T GetPlugin(Predicate<TMetadata> predicate)
{
Lazy<T, TMetadata> pluginInfo;
try
{
pluginInfo = plugins.SingleOrDefault(p => predicate(p.Metadata));
}
catch
{
// throw some exception
}
if (pluginInfo == null)
{
// throw some exception
}
return Clone(pluginInfo.Value); // -> this produces errors
}
}
I have a single object of Temp
and I call GetPlugin()
from multiple threads. Sometimes I face strange composition errors, which I didn't find a way to reproduce. For example:
"System.InvalidOperationException: Stack empty.
at System.Collections.Generic.Stack`1.Pop()
at System.ComponentModel.Composition.Hosting.ImportEngine.TrySatisfyImports(PartManager partManager, ComposablePart part, Boolean shouldTrackImports)
at System.ComponentModel.Composition.Hosting.ImportEngine.SatisfyImports(ComposablePart part)
at System.ComponentModel.Composition.Hosting.CompositionServices.GetExportedValueFromComposedPart(ImportEngine engine, ComposablePart part, ExportDefinition definition)
at System.ComponentModel.Composition.Hosting.CatalogExportProvider.GetExportedValue(CatalogPart part, ExportDefinition export, Boolean isSharedPart)
at System.ComponentModel.Composition.ExportServices.GetCastedExportedValue[T](Export export)
at System.Lazy`1.CreateValue()
at System.Lazy`1.LazyInitValue()
at Temp`2.GetPlugin(Predicate`1 predicate)..."
What could be a reason and how to cure this code?
The CompositionContainer
class has a little-known constructor which accepts an isThreadSafe
parameter (which defaults to false for performance reasons). If you'll create your container with this value set to true, I believe your problem will be solved:
CompositionContainer container = new CompositionContainer(aggregateCatalog, true);
On a side note, unrelated to the original question, instead of calling Clone()
on the plugin, you can use an export factory instead - this way you don't have to implement your own clone method, as MEF will create a new instance for you.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With