Caliburn.micro 如何使用 MEF 导入自定义插件
How Caliburn.micro uses MEF to import custom plugins
我在plugins目录下有一些扩展插件。我打算在ViewModel中导入插件并使用它,但我无法成功导入它。我想我没有办法成功配置Configure,求教。
引导程序:
public class AppBootstrapper : BootstrapperBase
{
private CompositionContainer container;
public AppBootstrapper()
{
Initialize();
}
protected override void Configure()
{
string pluginPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "plugins");
if (!Directory.Exists(pluginPath))
Directory.CreateDirectory(pluginPath);
var fi = new DirectoryInfo(pluginPath).GetFiles("*.dll");
AssemblySource.Instance.AddRange(fi.Select(fileInfo => Assembly.LoadFrom(fileInfo.FullName)));
var catalog = new AggregateCatalog(AssemblySource.Instance.Select(x => new AssemblyCatalog(x)).OfType<ComposablePartCatalog>());
var batch = new CompositionBatch();
container = new CompositionContainer(catalog);
batch.AddExportedValue(container);
batch.AddExportedValue<IWindowManager>(new WindowManager());
batch.AddExportedValue<IEventAggregator>(new EventAggregator());
batch.AddExportedValue(catalog);
container.Compose(batch);
}
protected override void BuildUp(object instance)
{
base.BuildUp(instance);
}
protected override object GetInstance(Type service, string key)
{
var contract = string.IsNullOrEmpty(key) ? AttributedModelServices.GetContractName(service) : key;
var exports = this.container.GetExportedValues<object>(contract);
if (exports.Any())
{
return exports.First();
}
throw new Exception(string.Format("Could not locate any instances of contract {0}.", contract));
}
protected override IEnumerable<object> GetAllInstances(Type service)
{
return this.container.GetExportedValues<object>(AttributedModelServices.GetContractName(service));
}
protected override void OnStartup(object sender, StartupEventArgs e)
{
DisplayRootViewFor<IShell>();
}
}
视图模型
[ImportMany]
IEnumerable<Lazy<IPlugin, IPluginsMetaData>> plugins;
其实我的Bootstrapper并没有问题,问题出现在我的IPluginclass。在查找问题的过程中,我还发现Bootstrapper的Configure方法是用另一种方式来写的。我会把整个插件的代码都贴出来供大家参考下~
BootStrapper 配置
protected override void Configure()
{
var catalog = new AggregateCatalog(AssemblySource.Instance.Select(x => new AssemblyCatalog(x)).OfType<ComposablePartCatalog>());
var batch = new CompositionBatch();
var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "plugins");
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
catalog.Catalogs.Add(new DirectoryCatalog(path));
container = new CompositionContainer(catalog);
batch.AddExportedValue(container);
batch.AddExportedValue<IWindowManager>(new WindowManager());
batch.AddExportedValue<IEventAggregator>(new EventAggregator());
batch.AddExportedValue(catalog);
container.Compose(batch);
}
ShellViewModel
[Export(typeof(IShell))]
public class ShellViewModel : Conductor<object>, IShell
{
[ImportMany]
IEnumerable<Lazy<IPlugin, IPluginMetaData>> plugins;
}
IPlugin
public interface IPlugin
{
void Do();
}
public interface IPluginMetaData
{
string Name { get; }
string Code { get; }
//[... more attribute ...]
}
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class PluginExportAttribute : ExportAttribute, IPluginMetaData
{
public string Name { get; set; }
public string Code { get; set; }
//[... more attribute ...]
public PluginExportAttribute() : base(typeof(IPlugin)) { }
}
PluginOne
[PluginExport(Name = "PluginOne", Code = "Key")]
public class PluginOne : IPlugin
{
public void Do()
{
Console.WriteLine("I'm PluginOne");
}
}
我在plugins目录下有一些扩展插件。我打算在ViewModel中导入插件并使用它,但我无法成功导入它。我想我没有办法成功配置Configure,求教。
引导程序:
public class AppBootstrapper : BootstrapperBase
{
private CompositionContainer container;
public AppBootstrapper()
{
Initialize();
}
protected override void Configure()
{
string pluginPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "plugins");
if (!Directory.Exists(pluginPath))
Directory.CreateDirectory(pluginPath);
var fi = new DirectoryInfo(pluginPath).GetFiles("*.dll");
AssemblySource.Instance.AddRange(fi.Select(fileInfo => Assembly.LoadFrom(fileInfo.FullName)));
var catalog = new AggregateCatalog(AssemblySource.Instance.Select(x => new AssemblyCatalog(x)).OfType<ComposablePartCatalog>());
var batch = new CompositionBatch();
container = new CompositionContainer(catalog);
batch.AddExportedValue(container);
batch.AddExportedValue<IWindowManager>(new WindowManager());
batch.AddExportedValue<IEventAggregator>(new EventAggregator());
batch.AddExportedValue(catalog);
container.Compose(batch);
}
protected override void BuildUp(object instance)
{
base.BuildUp(instance);
}
protected override object GetInstance(Type service, string key)
{
var contract = string.IsNullOrEmpty(key) ? AttributedModelServices.GetContractName(service) : key;
var exports = this.container.GetExportedValues<object>(contract);
if (exports.Any())
{
return exports.First();
}
throw new Exception(string.Format("Could not locate any instances of contract {0}.", contract));
}
protected override IEnumerable<object> GetAllInstances(Type service)
{
return this.container.GetExportedValues<object>(AttributedModelServices.GetContractName(service));
}
protected override void OnStartup(object sender, StartupEventArgs e)
{
DisplayRootViewFor<IShell>();
}
}
视图模型
[ImportMany]
IEnumerable<Lazy<IPlugin, IPluginsMetaData>> plugins;
其实我的Bootstrapper并没有问题,问题出现在我的IPluginclass。在查找问题的过程中,我还发现Bootstrapper的Configure方法是用另一种方式来写的。我会把整个插件的代码都贴出来供大家参考下~
BootStrapper 配置
protected override void Configure()
{
var catalog = new AggregateCatalog(AssemblySource.Instance.Select(x => new AssemblyCatalog(x)).OfType<ComposablePartCatalog>());
var batch = new CompositionBatch();
var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "plugins");
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
catalog.Catalogs.Add(new DirectoryCatalog(path));
container = new CompositionContainer(catalog);
batch.AddExportedValue(container);
batch.AddExportedValue<IWindowManager>(new WindowManager());
batch.AddExportedValue<IEventAggregator>(new EventAggregator());
batch.AddExportedValue(catalog);
container.Compose(batch);
}
ShellViewModel
[Export(typeof(IShell))]
public class ShellViewModel : Conductor<object>, IShell
{
[ImportMany]
IEnumerable<Lazy<IPlugin, IPluginMetaData>> plugins;
}
IPlugin
public interface IPlugin
{
void Do();
}
public interface IPluginMetaData
{
string Name { get; }
string Code { get; }
//[... more attribute ...]
}
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class PluginExportAttribute : ExportAttribute, IPluginMetaData
{
public string Name { get; set; }
public string Code { get; set; }
//[... more attribute ...]
public PluginExportAttribute() : base(typeof(IPlugin)) { }
}
PluginOne
[PluginExport(Name = "PluginOne", Code = "Key")]
public class PluginOne : IPlugin
{
public void Do()
{
Console.WriteLine("I'm PluginOne");
}
}