I am developing an application which uses the MEF to plug-in interfaces to external equipment (I/O devices, oscilloscopes, waveform generators etc). Most of these interfaces need DLLs to access the equipment and, when possible, I pack these DLLs into the project containing the plug-ins.
The application uses ImportMany
to load all classes which implement the plug-in interface. The user can then choose which interfaces are needed.
I have one interface which is causing me difficulties. I have not been able to identify all dependencies and when I start the application on another workstation I get an unresolved dependency error. I'm sure that when I install all the drivers and support DLLs then it would work ok.
However, not all users need to use this particular interface and I don't want to install all drivers on all workstations. I am looking for a way to degrade gracefully when some MEF plug-ins cannot be loaded. A log message would be enough to note that the interface could not be loaded. Only those trying to use the interface functions should get an error.
Here is my loader code:
try
{
var catalog = new AggregateCatalog();
var container = new CompositionContainer(catalog);
var batch = new CompositionBatch();
batch.AddPart(this);
catalog.Catalogs.Add(new AssemblyCatalog(typeof (Pruef.Net.TgtManager.TargetManager).Assembly));
container.Compose(batch);
_targets = _targets.OrderBy(t => t.DisplayName);
}
catch (Exception x)
{
log.Error(x);
}
This is what I did to avoid the error. Thanks to @Gusdor for pointing me in the right direction. Lazy-loading seems to be the way to go.
public class TargetManager
{
private static log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
[ImportMany(typeof(Pruef.Net.Contracts.ITarget))]
private IEnumerable<Lazy<Pruef.Net.Contracts.ITarget>> _targets;
public IEnumerable<Pruef.Net.Contracts.ITarget> AvailableTargets
{
get;
private set;
}
/// <summary>
/// Load all known target definitions
/// </summary>
public void Init()
{
try
{
var catalog = new AggregateCatalog();
var container = new CompositionContainer(catalog);
var batch = new CompositionBatch();
batch.AddPart(this);
catalog.Catalogs.Add(new AssemblyCatalog(typeof(Pruef.Net.TgtManager.TargetManager).Assembly));
container.Compose(batch);
List<ITarget> result = new List<ITarget>();
foreach (Lazy<ITarget> t in _targets)
{
try
{
result.Add(t.Value);
}
catch (Exception x)
{
// could not load plugin
// log error and continue
log.Error(x);
}
}
result = result.OrderBy(t => t.DisplayName).ToList();
AvailableTargets = result;
}
catch (Exception x)
{
log.Error(x);
}
}
}
}