MEF error, was a circular dependency and now something else

I have a circular dependency that has recently appeared due to a change in application architecture.

The application uses a plugin manager that downloads plugins via MEF. Everything worked fine, because it looked something like this:

// model.cs [Export("Model")] public class Model { public PluginManager PM { get; set; } [ImportingConstructor] public Model( [Import] PluginManager plugin_manager) { PM = plugin_manager; } } // pluginmanager.cs [Export(typeof(PluginManager))] public class PluginManager { [ImportMany(typeof(PluginInterface))] private IEnumerable<PluginInterface> Plugins { get; set; } } 

and plugins looked like this:

 // myplugin.cs [Export(typeof(PluginInterface))] public class MyPlugin : PluginInterface { } 

But now I have a situation where I want all the plugins to be able to request the PluginManager (or, possibly, any other object) through the interface to find out about other plugins in the system, to find out about their capabilities. I "solved" this by adding another interface, let me call it PluginQueryInterface. Then I used the Model of this interface.

 [Export("Model"))] [Export(typeof(PluginQueryInterface))] public class Model : PluginQueryInterface { // same as before } 

and then the plugin signature will look like this:

 // 1st possible implementation [Export(typeof(PluginInterface))] public class MyPlugin : PluginInterface { [Import(typeof(PluginQueryInterface))] public PluginQueryInterface QueryInterface { get; set; } public MyPlugin() {} } 

or

 // 2nd possible implementation [Export(typeof(PluginInterface))] public class MyPlugin : PluginInterface { private PluginQueryInterface QueryInterface { get; set; } [ImportingConstructor] public MyPlugin( [Import] PluginQueryInterface query_interface) { QueryInterface = query_interface } } 

The 2nd implementation is pretty clearly a round link because plugins require the creation of a PluginQueryInterface before creating the plugin, but the PluginQueryInterface is a model that should import the PluginManager, which in turn requires all the PluginInterfaces plugins to be created ... and when I start, I get an MEF dependency error.

The 1st implementation is not like a circular link to me. If PluginQueryInterface is a property, then I thought it would not be resolved until it was used . And it is not used by the constructor at all. So why not PluginManager have fun creating all my MyPlugins? I get the same MEF error in both cases.

I tried to solve this problem, making the PluginManager implement the PluginQueryInterface, because: a) it makes sense anyway and b) it is a known way to work with circular dependencies - they make two interdependent classes depend on the third class. Now the problem is that I get another MEF error ! Here is what he says:

 GetExportedValue cannot be called before prerequisite import 'Company.App.PluginManager..ctor(Parameter="database_filepath", ContractName="PluginManager.filename")' has been set. 

WTF? I set breakpoints in my code, and my exported value PluginManager.filename was set before calling GetExportedValue.

I am completely at a dead end. Any comments or suggestions will be greatly appreciated right now. I banged my head on the wall covered with MEF for several hours, trying to fix this problem.

(updated)

I did not think about this before, but it could be the differences between the plugins, so I removed one of the two plugins and now my application loads without MEF errors. I added it back and it failed again. Then I uninstalled another plugin and it worked. So it looks like this is another MEF error. It is almost as if I do not want me to load more than one plugin with a specific interface ... but I am using ImportMany, and will it not appear as a CardinalityException some kind?

UPDATE

I do not understand this part of MEF, and I hope someone here can explain what it is. After some time entering the code, I found that my error arose because the MEF removed the import definitions after finding the value!

  private bool TryGetImportValue(ImportDefinition definition, out object value) { lock (this._lock) { if (this._importValues.TryGetValue(definition, out value)) { this._importValues.Remove(definition); // this is the line that got me return true; } } value = null; return false; } 

I have never had this problem before, and frankly, it's hard for me to understand what I am doing now, with my imports and exports that created this problem. I guess I'm doing what the MEF designers weren't going to do. I could blindly comment on this._importValues.Remove(definition); but that could not be right. I assume this will work with the MEF attributes I used, but since the plugin that imports this value has a CreationPolicy.Shared creation policy, why do I have a problem?

+4
source share
2 answers

Well, I have a possible solution. I have no experience using this, but using Lazy seems to help. At least I can move forward without changing the MEF code, which I don't quite understand.

+3
source

It could also be a thread issue. You should try to build a container like ThreadSafe:

http://blogs.microsoft.co.il/blogs/zuker/archive/2011/01/02/mef-thread-safety-and-getexportedvalue.aspx

+3
source

All Articles