构建插件式的应用程序框架(五)-管理插件

我们现在已经搭建了插件式的应用程序框架,接下来的工作就是要充实框架的内容,提供基本的服务,也就是Service。我想首要的任务就是提供插件的管理服务,我在前面的文章也提到了,要实现动态加载必须要知道插件寄宿在哪里,哪些要加载,哪些不加载,这些就是这篇文章要讨论的问题。

首先解决的就是插件放在什么地方,我采取的传统的方法,将插件放到应用程序所在目录下的制定目录,我会在应用程序所在的目录下创建一个文件夹,命名为Plugins。接下来的工作就是要通知哪些插件是要加载的,哪些是不需要加载的,我会将这些信息放到应用程序的配置文件中的制定配置块中,当应用程序运行的时候,就会读取配置文件,并根据获得的信息加载插件。另外我们的应用程序框架是建立在Service基础之上,所以我需要创建一个管理插件的service。

我们现在定义一个插件管理的Service接口。

复制  保存

using System;
using System.Collections.Generic;
using System.Text;
namespace PluginFramework
{
public interface IPluginService
{
IApplication Application { get; set; }
void AddPlugin(String pluginName, String pluginType, String Assembly, String pluginDescription);
void RemovePlugin(String pluginName);
String[] GetAllPluginNames();
Boolean Contains(String pluginName);
Boolean LoadPlugin(String pluginName);
Boolean UnLoadPlugin(String pluginName);
IPlugin GetPluginInstance(String pluginName);
void LoadAllPlugin();
}
}

PluginService要实现的目标首先是在配置文件中添加/删除要加载的插件以及相关的信息,接下来就是动态的加载插件。我们要定义几个类型:Plugin配置区块类型,Plugin元素类型,plugin元素集合类型,以便我们能够读取插件的信息。

最后我们实现PluginService:

复制  保存

using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Configuration;
using System.Reflection;
using System.Windows.Forms;
using System.IO;
using System.Collections;
namespace PluginFramework
{
public class PluginService : IPluginService
{
private IApplication application = null;
private PluginConfigurationSection config = null;
private Dictionary<String, IPlugin> plugins = new Dictionary<string, IPlugin>();
private XmlDocument doc = new XmlDocument();
public PluginService()
{
}
public PluginService(IApplication application)
{
this.application = application;
}
IPluginService Members#region IPluginService Members
public void AddPlugin(string pluginName, string pluginType, string assembly, string pluginDescription)
{
doc.Load(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
XmlNode pluginNode = doc.SelectSingleNode("/configuration/PluginSection");
XmlElement ele = doc.CreateElement("add");
XmlAttribute attr = doc.CreateAttribute("Name");
attr.Value = pluginName;
ele.SetAttributeNode(attr);
XmlAttribute attrType = doc.CreateAttribute("Type");
attrType.Value = pluginType;
ele.SetAttributeNode(attrType);
XmlAttribute attrAss = doc.CreateAttribute("Assembly");
attrAss.Value = assembly;
ele.SetAttributeNode(attrAss);
XmlAttribute attrDes = doc.CreateAttribute("Description");
attrDes.Value = pluginDescription;
ele.SetAttributeNode(attrDes);
pluginNode.AppendChild(ele);
doc.Save(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
ConfigurationManager.RefreshSection("PluginSection");
}
public void RemovePlugin(string pluginName)
{
doc.Load(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
XmlNode node = doc.SelectSingleNode("/configuration/PluginSection");
foreach (XmlNode n in node.ChildNodes)
{
if (n.Attributes != null)
{
if (n.Attributes[0].Value == pluginName)
{
node.RemoveChild(n);
}
}
}
doc.Save(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
ConfigurationManager.RefreshSection("PluginSection");
}
public string[] GetAllPluginNames()
{
config = (PluginConfigurationSection)ConfigurationManager.GetSection("PluginSection");
PluginConfigurationElement pe = new PluginConfigurationElement();
ArrayList ps = new ArrayList();
for (Int32 i = 0; i < config.PluginCollection.Count; i++)
{
pe = config.PluginCollection[i];
ps.Add(pe.Name);
}
return (String[])ps.ToArray(typeof(String));
}
public bool Contains(string pluginName)
{
config = (PluginConfigurationSection)ConfigurationManager.GetSection("PluginSection");
PluginConfigurationElement pe = new PluginConfigurationElement();
List<String> ps = new List<string>();
for (Int32 i = 0; i < config.PluginCollection.Count; i++)
{
pe = config.PluginCollection[i];
ps.Add(pe.Name);
}
return ps.Contains(pluginName);
}
public bool LoadPlugin(string pluginName)
{
Boolean result = false;
config = (PluginConfigurationSection)ConfigurationManager.GetSection("PluginSection");
PluginConfigurationElement pe = new PluginConfigurationElement();
String path = Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath) + """Plugin";
try
{
for (Int32 i = 0; i < config.PluginCollection.Count; i++)
{
pe = config.PluginCollection[i];
if (pe.Name == pluginName)
{
Assembly assembly = Assembly.LoadFile(path + """" + pe.Assembly);
Type type = assembly.GetType(pe.Type);
IPlugin instance = (IPlugin)Activator.CreateInstance(type);
instance.Application = application;
instance.Load();
plugins[pluginName] = instance;
result = true;
break;
}
}
if (!result)
{
MessageBox.Show("Not Found the Plugin");
}
}
catch (Exception e)
{
MessageBox.Show(e.Message);
result = false;
}
return result;
}
public bool UnLoadPlugin(string pluginName)
{
Boolean result = false;
try
{
IPlugin plugin = GetPluginInstance(pluginName);
plugin.UnLoad();
result = true;
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
return result;
}
public void LoadAllPlugin()
{
PluginConfigurationElement pe = new PluginConfigurationElement();
config = (PluginConfigurationSection)ConfigurationManager.GetSection("PluginSection");
String path = Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath) + """Plugin";
try
{
for (Int32 i = 0; i < config.PluginCollection.Count; i++)
{
pe = config.PluginCollection[i];
Assembly assembly = Assembly.LoadFile(path + """" + pe.Assembly);
Type type = assembly.GetType(pe.Type);
IPlugin instance = (IPlugin)Activator.CreateInstance(type);
instance.Application = application;
instance.Load();
plugins[pe.Name] = instance;
}
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
}
public IApplication Application
{
get
{
return application;
}
set
{
application = value;
}
}
public IPlugin GetPluginInstance(string pluginName)
{
IPlugin plugin = null;
if (plugins.ContainsKey(pluginName))
{
plugin = plugins[pluginName];
}
return plugin;
}

#endregion
    }
}

由于代码比较多,我也就不一一列举了,只把比较重要的代码列出来,其余的我会提供源代码的下载。在实现了PluginService以后,我们需要有一个地方能够使用这个Service来管理插件,我的做法是在一个菜单里添加一个项目,当用户点击这个项目的时候弹出插件管理的对话框,用户在这个对话框中选择使用那些插件,当插件被选中的时候,插件会被立即加载进来,并且记录到配置文件里,当用户下次运行应用程序的时候,插件默认会被自动的加载。

另外从现在开始我们就需要使用配置文件了,所以,我们需要给应用程序添加一个app.config文件,文件内容如下:

复制  保存

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section
name="PluginSection"
type="PluginFramework.PluginConfigurationSection, PluginFramework"
/>
</configSections>
<PluginSection>
</PluginSection>
</configuration>

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section
name="PluginSection"
type="PluginFramework.PluginConfigurationSection, PluginFramework"
/>
</configSections>
<PluginSection>
</PluginSection>
</configuration>

样子,总体来说我们就为Plugin的管理提供了一个基本的实现,如果大家还有什么不明白的地方,可以参考我提供的源代码或者通过e-mail和我联系。

源代码下载
http://files.cnblogs.com/guanjinke/pluginsample2.rar

时间: 2024-09-20 12:27:06

构建插件式的应用程序框架(五)-管理插件的相关文章

构建插件式的应用程序框架(六)-通讯机制

有几个朋友在回复中希望了解插件之间是如何通讯的. 这个系列的文章写到这里,也该谈谈这个问题了,毕竟已经有了插件管理.不知道大家有没有注意到我在第四篇文章里谈到的服务容器(Service Container),Service是我所提到的插件式的应用程序框架的基础,我们也可以回头看看IApplication的接口定义,IApplication是派生于IServiceContainer.我把应用程序提供的相关的功能抽象成一个一个的Service,比如文档管理的,我们就抽象成IDocumentServi

构建插件式的应用程序框架(一)----订立契约

问题描述 无论是用COM的方式,还是普通DLL,抑或.NET方式来实现插件框架,首先要面临的问题就是如何订立契约.如同我上一篇文章讲到的一样,契约是应用程序和插件之间进行交互的依据和凭证.应用程序必须声明我有什么样的功能可被插件使用,并且插件必须符合什么条件才能被我使用.反之,插件必须要知道应用程序提供什么样的功能,我才能将自己的功能融入到应用程序的体系中.本系列文章主要讲如何使用.NET实现插件式的应用程序框架,所以其它的方式我就不再提了.如何使用.NET订立契约呢?首先想到的Interfac

构建插件式的应用程序框架(三)-动态加载

不管你采用什么方式实现插件式的应用程序框架,核心还是动态加载,换句话说,没有动态加载技术也就无所谓插件式的应用程序框架了.使用Com实现的话,你可以利用Com的API通过ProgID来动态创建COM对象,如果使用普通DLL,你需要使用Windows 的API函数LoadLibrary来动态加载DLL,并用GetProcAddress函数来获取函数的地址.而使用.NET技术的话,你需要使用Assembly类的几个静态的Load(Load,LoadFile,LoadFrom)方法来动态加载汇集. 一

构建插件式的应用程序框架(一)-开篇

说起插件(plug-in)式的应用程序大家应该不陌生吧,记得很早以前有一款很流行的MP3播放软件winmap,它是我记忆里最早认识的一款使用插件模式的应用程序,你可以使用他的插件管理器插入很多的音乐效果器,皮肤,甚至是歌词显示的面板.接下来看到了Photoshop使用插件模式管理虑镜.最后发现只要是大一点的应用程序基本都使用了插件式的程序框架,就拿我们最常用的工具来说吧,Visual Studio,Office,Delphi,Eclipse等等.Eclipse将插件模式发挥到了及至,因为他是开源

构建插件式的应用程序框架(四)-服务容器

IApplication接口是派生于IServiceContainer接口的.为什么要派生于IServiceContainer呢?我们来看看IServiceContainer的定义,它有几个AddService方法和RemoveService方法以及从IserviceProvider继承过来的GetService方法.Service本身是.NET设计时架构的基础,Service提供设计时对象访问某项功能的方法实现,说起来还真拗口.就我看来,ServiceContainer机制的本质就是解耦合,就

构建插件式的应用程序框架(二)-订立契约

无论是用COM的方式,还是普通DLL,抑或.NET方式来实现插件框架,首先要面临的问题就是如何订立契约.如同我上一篇文章讲到的一样,契约是应用程序和插件之间进行交互的依据和凭证.应用程序必须声明我有什么样的功能可被插件使用,并且插件必须符合什么条件才能被我使用.反之,插件必须要知道应用程序提供什么样的功能,我才能将自己的功能融入到应用程序的体系中.本系列文章主要讲如何使用.NET实现插件式的应用程序框架,所以其它的方式我就不再提了. 如何使用.NET订立契约呢?首先想到的Interface,其次

构建插件式的应用程序框架(七)-基本服务

既然做好了框架,我们就希望为某个目标服务,我们要提供一些基本的服务,方便用户继续扩展他的功能.首先想到的功能就是,菜单,工具栏的管理,接下来我们要实现一些更流行的功能,比如停靠工具栏等等. 如何实现这些服务呢?我们希望我们的插件在运行时可以获得应用程序本身的菜单,工具条,停靠工具栏等等,然后向他们添加项目,比如加入一个菜单项,添加一个工具栏按钮.为了在运行时获得某个菜单或者工具栏,我们要为每一个菜单后者工具栏分配一个Key,然后放到一个词典中,当需要的时候,我们通过这个key来获得实例.对于这个

构建插件式的应用程序框架(八)-视图服务的简单实现

我在前一篇文章里提到,对于停靠工具栏或者是视图最好是不要将实例放到词典中,而是将工具栏或者视图的类型放到词典中,因为视图类型会经常的被重用,并且会经常被关闭或者再打开.当实例被关闭后,资源就被释放了,对于实例的管理就会比较麻烦,所以我们分为两步走.在插件被加载的时候,我们只注册类型,在应用程序运行的时候,我们通过某种途径来实例化他. 我修改的以前的例子,主要突出本次演示的功能.这次的例子实现的功能是通过插件扩展应用程序处理不同文件的能力.在原始的应用程序中,我们可以通过File菜单的Open,只

现完成了一套插件式构架的程序,用VS2005打包,能不能做到安装时选择了那些插件,才把相应插件的DLL安装进客户机去?

问题描述 现完成了一套插件式构架的程序,用VS2005打包,能不能做到安装时选择了那些插件,才把相应插件的DLL安装进客户机去? 解决方案 解决方案二:有人知道嘛?或者提下思路也好啊......解决方案三:顶上去..........解决方案四: 解决方案五:没人知道嘛?还是.NET自己打包,没法实现这种功能?一定要先把所以的DLL文件都COPY到客户机的?解决方案六:小顶一下解决方案七:可能你要自己在Setup程序里面写自定义的安装步骤,没写过具体也没办法告诉你你可以考虑InstallShiel