This is sort of a continuation of one of my earlier posts, which involves the resolving of modules in my WPF application. This question is specifically related to the effect of interdependencies of modules and the method of constructing those modules (i.e. via MEF or through new
) on MEF's ability to resolve relationships.
First of all, here is a simple UML diagram of my test application:
I have tried two approaches:
- left approach: the App implements IError
- right approach: the App has a member that implements IError
Left approach
My code behind looked like this (just the MEF-related stuff):
// app.cs
[Export(typeof(IError))]
public partial class Window1 : Window, IError
{
[Import]
public CandyCo.Shared.LibraryInterfaces.IPlugin Plugin { get; set; }
[Import]
public CandyCo.Shared.LibraryInterfaces.ICandySettings Settings { get; set; }
private ICandySettings Settings;
public Window1()
{
// I create the preferences here with new, instead of using MEF. I wonder
// if that's my whole problem? If I use MEF, and want to have parameters
// going to the constructor, then do I have to [Export] a POCO (i.e. string)?
Settings = new CandySettings( "Settings", @"c:\settings.xml");
var catalog = new DirectoryCatalog( ".");
var container = new CompositionContainer( catalog);
try {
container.ComposeParts( this);
} catch( CompositionException ex) {
foreach( CompositionError e in ex.Errors) {
string description = e.Description;
string details = e.Exception.Message;
}
throw;
}
}
}
// plugin.cs
[Export(typeof(IPlugin))]
public class Plugin : IPlugin
{
[Import]
public CandyCo.Shared.LibraryInterfaces.ICandySettings CandySettings { get; set; }
[Import]
public CandyCo.Shared.LibraryInterfaces.IError ErrorInterface { get; set; }
[ImportingConstructor]
public Plugin( ICandySettings candy_settings, IError error_interface)
{
CandySettings = candy_settings;
ErrorInterface = error_interface;
}
}
// candysettings.cs
[Export(typeof(ICandySettings))]
public class CandySettings : ICandySettings
{
...
}
Right-side approach
Basically the same as the left-side approach, except that I created a class that inherits from IError in the same assembly as Window1. I then used an [Import] to try to get MEF to resolve that for me.
Can anyone explain how the two ways I have approached MEF here are flawed? I have been in the dark for so long that instead of reading about MEF and trying different suggestions, I've added MEF to my solution and am stepping into the code. The part where it looks like it fails is when it calls partManager.GetSavedImport()
. For some reason, the importCache is null, which I don't understand. All the way up to this point, it's been looking at the part (Window1) and trying to resolve two imported interfaces -- IError and IPlugin. I would have expected it to enter code that looks at other assemblies in the same executable folder, and then check it for exports so that it knows how to resolve the imports...
I had found a mistake in my code, and when I fixed it, the MEF exception changed, and was also more useful. It clearly pointed out that it couldn't find a CandySettings default constructor! And digging more, I found a good post from Glenn Block that discusses this. So I need to finish reading it and see if his workaround will do the trick or not. I would still appreciate more answers, since there's no telling if the workaround is the right thing to do or not.