我们现在已经搭建了插件式的应用程序框架,接下来的工作就是要充实框架的内容,提供基本的服务,也就是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