I am trying to implement a plugin architecture for our WPF program following the proposed implementation here. I want my plugins to reside in a separate folder from the main program folder. I have gotten it to only partially work. Here is the code:
The plan is for each plugin to provide its own StructureMap registry to override the default StructureMap regstry.
The plugin I am currently working on has the following registry and as you can see, I am overriding the registry for the plugin-type IPrintProgramExecutor to intercept and use AutomationController instead. And it works as expected:
public class PluginRegistry : Registry
{
public PluginRegistry()
{
this.ForConcreteType<AutomationController>()
.Configure
.Ctor<IPrintProgramExecutor>().Is(c=> c.GetInstance<PrintProgramExecutor>())
.Singleton();
this.For<IAutomationController>().Use(c => c.GetInstance<AutomationController>()).Singleton();
this.For<IPrintProgramExecutor>().Use(c => c.GetInstance<IAutomationController>()).Singleton();
//this.ForConcreteType<AutomationPlugin>()
// .Configure
// .Singleton();
this.For<IPluginBase>().Use<AutomationPlugin>();
}
}
AutomationPlugin currently is this stub:
public class AutomationPlugin : IPluginBase
{
public ViewModelBase ViewModel {
get { return viewModel; }
private set { viewModel = value; }
}
public ResourceDictionary View { get; }
private ViewModelBase viewModel { get; set; }
private ResourceDictionary viewDictionary = new ResourceDictionary();
public AutomationPlugin()
{
// do something meaningfull!
}
}
with IPluginBase:
public interface IPluginBase
{
ViewModelBase ViewModel { get; }
ResourceDictionary View { get; }
}
The class to add the registry is this, where pluginPath is the path to the extension folder:
public class PluginRegistryAdder : Registry
{
public PluginRegistryAdder(string pluginPath)
{
Scan( x =>
{
x.AssembliesFromPath(pluginPath);
x.LookForRegistries();
});
}
}
The class to actually tie in the plugin registry using the code above is this:
public static class ExtensionManager
{
public static void RegisterPluginsInDic(string pluginPath, IContainer container)
{
var pluginRegistries = new PluginRegistryAdder(pluginPath);
container.Configure(_ => _.IncludeRegistry(pluginRegistries));
var whatIHave = container.WhatDoIHave(typeof(IPluginBase));
var plugins = container.Model.GetAllPossible<IPluginBase>(); // the IEnumerable plugins is empty although I am registering `AutomationPlugin` for it. Why?!
}
}
Now, as mentioned above, the interception for the plugin-type IPrintProgramExecutor works as expected. But for some reason container.Model.GetAllPossible<IPluginBase>() and container.WhatDoIHave(typeof(IPluginBase)) do not find any registered types for the plugin-type IPluginBase. I have tried calling these methods for IPrintProgramExecutor and surely enough they return the concrete type. I have been looking quite a while for the reason and cannot find it.
Any ideas why? Could it have to do with the fact, that I am calling container.Configure(...) twice and perhaps the fact that I already register something for IPringProgramExecutor the first time I call container.Configure(...)? Help is greatly appreciated!
Updates:
- After switching to my laptop, the interception, that previously worked, does not work anymore. Furthermore, I am now getting an exception, that one of the assemblies I am trying to register in
PluginRegistryis not found:
StructureMap.StructureMapException: Unable to create an instance for Registry type 'Extensions.Automation.PluginRegistry'. Please check the inner exception for details ---> System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.IO.FileNotFoundException: Could not load file or assembly 'Automation.Servers.Interfaces, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified. at Extensions.Automation.PluginRegistry..ctor() ...
All in all, it seems like a path-problem that I cannot figure out. I suspect, that at run-time the program attempts to load the DLLs in the Plugin-registry from the main path, but the corresponding DLLs/asseblies reside in the Extension-folder. How can I see from where StructureMap attempts to load the assembly Automation.Servers.Interfaces for debugging? Hope somebody can help me out. I am slowly loosing it.