给IBuySpy构建一个PlugIn系统

话说公元2003年12月17日,MSDN Library网站上悄无声息的多了一篇文章,介绍了关于构建一个PlugIn Framework的一些基础知识,于是,有了这篇随笔…
  
  PlugIn,很COOL的特性,下面将演示如何给我们的IBuySpy定制一个Page Start PlugIn,这个PlugIn可以让用户自己来创建PlugIn,嵌入到IBuySpy的Page Start PlugIn里面,在网站页面载入的时候,会执行用户嵌入的PlugIn。
  
  可我们为什么要给IBuySpy创建PlugIn接口呢?我们要实现同样的功能,可以直接的修改它的代码,岂不是直接很多?原因:IBuySpy只是用来演示PlugIn的,你可以把同样的技术应用到其他的WebForm甚至WinForm,而它们可能并不会像IBuySpy一样是免费的,我们交付的产品里面不会附上代码,如果我们提供了PlugIn的接口,无疑会让我们的产品更加具有扩展性。何况很多功能可能可以直接作成PlugIn来嵌入到原有的系统中,这个时候无需再改动原有的代码,再去编译它。
  
  1、构建IBuySpy的PlugIn所需的接口,这些接口就是可以公开给用户代码的:
  
  首先需要的是一个通用的IPlugIn接口,所有具体的插件将实现这个接口:
  
  namespace ASPNetPortal.PlugIns {
  
   public interface IPlugIn {
   String Name {get;}
   String Version {get;}
   void DoAction(IPlugInArgs args);
   }
  }
  
  这个接口有三个成员:
  Name属性,公开插件的名称
  Version属性,公开插件的版本
  DoAction()方法,执行插件要做的操作,这个方法还有一个IPlugInArgs的参数,需要传递给方法所参数可以通过它传递出去。
  
  然后就是这个IPlugInArgs接口:
  
  namespace ASPNetPortal.PlugIns {
  
   public interface IPlugInArgs {
   System.Web.HttpContext Context {get;}
   Object Data {get;}
   }
  }
  
  它有两个成员:
  Context属性,一个HttpContext类型的对象,如果我们要让插件能够在页面上做些事,不给它HttpContext肯定不行。
  Data属性,一个Object类型的对象,预留的,什么地方需要就什么地方用上。
  
  接着是一个接口集合类:
  
  namespace ASPNetPortal.PlugIns {
  
   public class PlugInCollection : CollectionBase {
  
   public Int32 Add(IPlugIn plugIn) {
   return this.List.Add(plugIn);
   }
  
   public IPlugIn this[Int32 index] {
   get {
   return (IPlugIn) this.List[index];
   }
   }
   }
  }
  
  很简单明了。用户可能不止嵌入一个插件。
  
  PlugIn也可以有很多类型,比如我们这里要实现的Page Start PlugIn,是一个在页面载入的时候可以让嵌入的PlugIn执行的。当然你也可以创建各种类型的PlugIn。
  
  namespace ASPNetPortal.PlugIns {
  
   public interface IPageStartPlugIn : IPlugIn {}
  }
  
  这个PlugIn接口不需要再做任何事,直接继承IPlugIn就可以了。
  
  2、修改IBuySpy,让它支持执行PlugIn:
  
  根据我们的需求,我们创建一个实际的插件参数类,这个类继承自IPlugInArgs:
  
  namespace ASPNetPortal.PlugIns {
  
   public class PlugInArgs : IPlugInArgs {
   private System.Web.HttpContext _context;
   private Object _data;
  
   public PlugInArgs(System.Web.HttpContext context, Object data) {
   _context = context;
   _data = data;
   }
  
   public System.Web.HttpContext Context {
   get {
   return _context;
   }
   }
  
   public Object Data {
   get {
   return _data;
   }
   }
   }
  }
  
  我们需要地方来标示用户嵌入的PlugIn的列表,我们放在web.config里面的里面,我们加上一项,来表示我们要添上的Page Start PlugIn:
  
  《ADD key="PageStartPlugIns" value="" /》
  
  value里面可以写入嵌入的PlugIn的列表,格式像这样:Value = "插件一的类名, 插件一的程序集名; 插件二的类名, 插件二的程序集名"
  
  然后,我们构建一个PlugInHelper类,来执行获取PlugIn、执行PlugIn的操作:
  
  namespace ASPNetPortal.PlugIns {
  
   public class PlugInHelper {
  
   private PlugInHelper() {}
  
   public static PlugInCollection GetPlugIns(String plugInType) {
   PlugInCollection plugIns = new PlugInCollection();
   String sPageStartPlugIns = System.Configuration.ConfigurationSettings.AppSettings[plugInType];
   if ((sPageStartPlugIns != null) && (sPageStartPlugIns != "")) {
   String[] asPlugInStr = sPageStartPlugIns.Split(';'); foreach(String plugInStr in asPlugInStr) {
   plugIns.Add( (IPageStartPlugIn) System.Activator.CreateInstance(System.Type.GetType(plugInStr)));
   }
   }
   return plugIns;
   }
  
   public static void ExecutePlugIns(PlugInCollection plugIns, IPlugInArgs args) {
   foreach(IPlugIn plugIn in plugIns) {
   plugIn.DoAction(args);
   }
   }
   }
  }
  
  GetPlugIns()方法返回指定类型的PlugIn的列表,返回类型是PlugInCollection,ExecutePlugIns()用来执行参数中的PlugIn。
  
  最后,我们要把执行插件的代码加入到页面的执行队列中。为了在每个页面开始的时候能够执行用户嵌入的Page Start Plug,标准方法是在Global.asa里面来实现,更标准的方法是构建一个httpModule,然后在这个httpModule中来执行这个PlugIn(关于构建自定义的httpModule,辣椒是个中高手)。我这里就偷懒了,因为IBuySpy几乎所有的内容页面都是DesktopDefault.aspx这个页面中载入,所以我们先在这个页面里面创建一个方法来执行插件:
  
  private void PerformPlugIns() {
   PlugInCollection plugIns = PlugInHelper.GetPlugIns("PageStartPlugIns");
   PlugInArgs args = new PlugInArgs(Context, null);
   PlugInHelper.ExecutePlugIns(plugIns, args);
  }
  
  第一句得到所有的Page Start PlugIn,第二句创建一个传递给插件的PlugInArgs对象,第三句调用PlugInHelper.ExecutePlugIns()来执行第一句得到的PlugIn队列。
  
  在DesktopDefault.aspx的Page_Init事件中调用上面的这个PerformPlugIns()方法就OK了。
  
  3、演示如何创建一个Page Start PlugIn:
  
  前面两步已经让IBuySpy可以嵌入用户自定义的Page Start PlugIn了,现在我们来做一个实际的PlugIn嵌进去。
  
  启动VS,创建一个“C#类库”项目,引入IBuySpy的程序集Portal.dll,这是因为我们需要用到IBuySpy里面的PlugIn相关的那些接口,更好的方法是把IBuySpy中与PlugIn相关的公共接口放在一个单独的程序集里面。
  
  namespace WelcomeMessage {
  
   public class ShowWelcome : ASPNetPortal.PlugIns.IPageStartPlugIn {
  
   public string Name {
   get {
   return "Show Page Welcome Message";
   }
   }
  
   public string Version {
   get {
   return "1.0.0.1";
   }
   }
  
   public void DoAction(IPlugInArgs args) {
   args.Context.Response.Write(“<_script_>alert(‘Hello, world!’);”); // 故意写错了,不然...
  }
  }
  }
  
  这个ShowWelcome类继承自IPageStartPlugIn,表示它是一个Page Start PlugIn,用来具体执行操作的DoAction()方法只做了一件事,从参数中得到页面相关的HttpContext对象,然后输出一段字符以在页面内容载入之前弹出一个“Hello,world!”的提示框。
  
  然后我们修改IBuySpy的web.config里面相关的那句设定:
  
  《ADD value="WelcomeMessage.ShowWelcome, WelcomeMessage" key="PageStartPlugIns" /》
  
  OK了,编译,把生成的dll放到IBuySpy的bin目录,打开浏览器浏览IBuySpy网站,你会看到每次载入页面内容时,都会弹出一个“Hello,world!”的提示框。

时间: 2024-12-31 20:09:59

给IBuySpy构建一个PlugIn系统的相关文章

构建一个简单的CaaS系统_docker

在CaaS系统出现前企业应用架构基本被IaaS/SaaS/PaaS等模式垄断,直到Docker的出现为我们打开了另一个扇大门,废话不说了,我们直奔主题. 我们先了解下一个简单的CaaS系统是如何为用户提供服务的: 企业用户上传它的应用代码或其他代码托管方式,我们生成用户应用的镜像,或者用户直接上传镜像,或者用户直接使用我们提供的基础服务镜像 用户部署他的镜像应用,启动它的镜像容器 用户访问他的应用服务 OK,需求确定了,该搬砖了. 用户镜像制作 既然是一个简单的CaaS系统,我们就不让用户上传代

如何在运维场景中构建一个优秀精准的异常检查系统

在实际的运维场景中,构建一个异常检测系统往往需要两个角色共同参与:领域专家和算法开发人员.领域专家也就是我们的运维人员,他们对KPI曲线的行为很熟悉,可以通过观察KPI曲线并结合自己的领域知识,判断KPI曲线是否出现异常:算法开发人员负责构建异常检测系统,他们熟悉异常检测器(算法),但是实际中有各种不同类型的KPI曲线需要维护,所以需要为不同类型的KPI曲线选择合适的异常检测器以及合适的算法参数. 在实际构建异常检测系统时,首先需要运维人员结合自己的领域知识向算法开发人员描述异常,然后开发人员根

如何构建一个简单的CAAS系统

在CAAS系统出现前企业应用架构基本被IAAS/SAAS/PAAS等模式垄断,直到docker的出现为我们打开了另一个扇大门,废话不说了,我们直奔主题 我们先了解下一个简单的CAAS系统是如何为用户提供服务的 企业用户上传它的应用代码或其他代码托管方式,我们生成用户应用的镜像,或者用户直接上传镜像,或者用户直接使用我们提供的基础服务镜像 用户部署他的镜像应用,启动它的镜像容器 用户访问他的应用服务 OK,需求确定了,该搬砖了. 1. 用户镜像制作 既然是一个简单的CAAS系统,我们就不让用户上传

先做点好事,转点东东来,用PHP和MySQL构建一个数据库驱动的网站(-)

mysql|数据|数据库 摘要 在这篇文章中,我们会着手解决在构建一个数据库驱动的网站的过程中将会遇到的问题.而我们只会使用两个新的工具,PHP和MySQL.如果你的Web主机支持PHP/MySQL,那么你会省掉不少麻烦.如果不是这样,你也不用提心,我们也会学习如何在Unix和Windows下安装相应程序. 这篇文章是提供给那些有可能学会服务器端程序开发的中高级的网页设计者的.我们会认为我们的读者熟悉HTML,所以我们在使用HTML时不会给出什么解释.另外,在有些地方我们可能还会用到少量的Jav

【OSGI】2.走近OSGI-开发第一个Plug-in项目

上一次我们介绍了什么是OSGI和OSGI在我们的项目中起到了什么作用.这次我们来亲手使用OSGI技术. 主要利用Eclipse开发工具提供给我们的plug-in插件工程模板来创建我们的工程.零距离的体验一下OSGI项目创建的基本过程,和运行流程以及其它相关的知识. 所有语言或技术的第一次测试通常都会以"HelloWorld"作为代表性语句,那么我们接下来将利用OSGI技术,创建一个HelloWorld的插件工程. (1)创建项目 在Eclipse中我们首先新建一个"plug-

Python中的线性优化,第 2 部分 在云中构建一个可扩展的基础架构

简介 这个由三部分组成的系列文章的第 1 部分介绍了在 Python 中使用 Pyomo 库进行线性优化的 基础知识.现在我们将介绍如何扩展它.Python 缺乏真实的操作系统线程,该如何扩展它?本文将向您介绍 如何组合使用这些技术来创建一个实际的可扩展基础架构,该架构可用于构建一个 Pyomo Web 解决方案.我 们组合使用了一个单线程事件循环.一个 AMQP 服务器和工作线程流程来创建一个模式,利用该模式扩展一个 线性优化系统.该基础架构也适用于 Python 或 Ruby 中的许多通用计

用Java Servlet构建旗帜广告系统

对于一个商务网站来说,广告系统是必不可少的.一个好的广告系统是一个网站稳定收入的基础.而旗帜广告(banner)则是网站广告中占绝大部分的广告,因此开发一个旗帜广告系统就非常重要了.利用Java Servlet 我们可以很轻松的构建属于我们自己的旗帜广告系统. 我们一般在网页上放上一些图片,设置它们的链接指向广告客户的网页,然后产生日志文件存放浏览的人数,浏览者的IP等信息,这就是开发旗帜广告系统的一般思路. 下面,我想结合一个例程来介绍一下如何使用Java Servlet来构建旗帜广告系统.这

用PHP和MySQL构建一个数据库驱动的网站(十)

mysql|数据|数据库 在我们目前的情况下,我们所需要的列是Jokes表中的JokeText列以及Authors表中的Name列和Email列.Jokes表和Authors表的关联条件是Jokes表中的AID列的值等于Authors表中的ID列的值.下面是一个连接的例子(前两个查询只是用来显示我们的两个表中所包含的内容): mysql> SELECT LEFT(JokeText,20), AID FROM Jokes;+----------------------+------+| LEFT(

用PHP和MySQL构建一个数据库驱动的网站(六)

mysql|数据|数据库 摘要 在这一章内我们会学习到如何在一个Web页面中向数据库中存储信息并显示它. (2002-08-29 14:11:25) --------------------------------------------------------------------------------By Wing, 出处:Linuxaid 第四章: 用PHP访问MySQL数据库 在这一章内我们会学习到如何在一个Web页面中向数据库中存储信息并显示它.之前我们已经安装了MySQL这个关系