Tim*_*ong 7 plugins mef composition
我正在考虑使用MEF来解决插件管理要求.在模糊中它表示"没有硬依赖",但据我所知,导入/导出界面存在严重依赖.
我担心的是这个.我的可扩展应用程序是由我编写的.插件由第三方编写.所以我们都说从V1开始.我的应用程序定义了IPlugin插件"部件"需要实现的接口.我们部署应用程序,用户安装了一堆第三方插件.一切都很好.
现在我升级了我的应用程序,我想在插件界面中添加一个新方法.我看到它的方式我有两个选择:
创建一个新的'V2'接口,继承自原始接口
公共接口IPluginV2:IPlugin {}
现在我有一个问题.我的用户都有一堆第三方插件实现IPlugin,但我现在要求他们实现IPluginV2.我认为这些第三方插件将不再有效,直到开发人员实现新界面.
MEF有办法处理这种情况吗?我真的在寻找一种让我可以改进我的应用程序的方法,同时让旧的插件继续工作而不必重建.什么是最好的处理方式?
Pan*_*nis 13
对于版本控制,您可能希望每个版本的接口和适配器模式在它们之间.它是如何System.AddIn处理版本控制的,它也适用于MEF.
假设我们为您的应用程序的V1提供以下类型:
public interface IPlugin
{
string Name { get; }
string Publisher { get; }
string Version { get; }
void Init();
}
Run Code Online (Sandbox Code Playgroud)
这是我们的V1插件感知应用程序的唯一合同.它包含在组件中Contracts.v1.
然后我们有一个 V1插件:
[Export(typeof(IPlugin))]
public class SomePlugin : IPlugin
{
public string Name { get { return "Some Plugin"; } }
public string Publisher { get { return "Publisher A"; } }
public string Version { get { return "1.0.0.0"; } }
public void Init() { }
public override string ToString()
{
return string.Format("{0} v.{1} from {2}", Name, Version, Publisher);
}
}
Run Code Online (Sandbox Code Playgroud)
哪个导出为IPlugin.它包含在程序Plugin.v1集中,并发布在主机应用程序基本路径下的"plugins"文件夹中.
最后V1主持人:
class Host : IDisposable
{
CompositionContainer _container;
[ImportMany(typeof(IPlugin))]
public IEnumerable<IPlugin> Plugins { get; private set; }
public Host()
{
var catalog = new DirectoryCatalog("plugins");
_container = new CompositionContainer(catalog);
_container.ComposeParts(this);
}
public void Dispose() { _container.Dispose(); }
}
Run Code Online (Sandbox Code Playgroud)
导入IPlugin文件夹"plugins"中的所有部件.
然后我们决定发布V2,因为我们想要提供版本控制,我们需要无版本的合同:
public interface IPluginV2
{
string Name { get; }
string Publisher { get; }
string Version { get; }
string Description { get; }
void Init(IHost host);
}
Run Code Online (Sandbox Code Playgroud)
使用新属性和修改后的方法签名.另外,我们为主机添加了一个界面:
public interface IHost
{
//Here we can add something useful for a plugin.
}
Run Code Online (Sandbox Code Playgroud)
这两个都包含在程序集中Contracts.v2.
为了允许版本控制,我们添加了一个从V1到V2的插件适配器:
class V1toV2PluginAdapter : IPluginV2
{
IPlugin _plugin;
public string Name { get { return _plugin.Name; } }
public string Publisher { get { return _plugin.Publisher; } }
public string Version { get { return _plugin.Version; } }
public string Description { get { return "No description"; } }
public V1toV2PluginAdapter(IPlugin plugin)
{
if (plugin == null) throw new ArgumentNullException("plugin");
_plugin = plugin;
}
public void Init(IHost host) { plugin.Init(); }
public override string ToString() { return _plugin.ToString(); }
}
Run Code Online (Sandbox Code Playgroud)
这简单地适应IPlugin了IPluginV2.它返回一个固定的描述,并在Init它没有采取任何与宿主的说法,但它调用的参数的Init从V1的合同.
最后V2主机:
class HostV2WithVersioning : IHost, IDisposable
{
CompositionContainer _container;
[ImportMany(typeof(IPluginV2))]
IEnumerable<IPluginV2> _pluginsV2;
[ImportMany(typeof(IPlugin))]
IEnumerable<IPlugin> _pluginsV1;
public IEnumerable<IPluginV2> Plugins
{
get
{
return _pluginsV1.Select(p1 => new V1toV2PluginAdapter(p1)).Concat(_pluginsV2);
}
}
public HostV2WithVersioning()
{
var catalog = new DirectoryCatalog("plugins");
_container = new CompositionContainer(catalog);
_container.ComposeParts(this);
}
public void Dispose() { _container.Dispose(); }
}
Run Code Online (Sandbox Code Playgroud)
这两者都导入IPlugin和IPluginV2零件,以适应每个IPlugin进入IPluginV2 ,并公开所有发现的插件连接序列.完成调整后,所有插件都可以视为V2插件.
您还可以在主机接口上使用适配器模式,以允许V2插件与V1主机一起使用.
另一种方法是autofac IoC,它可以与MEF 集成,并且可以使用适配器支持版本控制.