給IBuySpy構建一個PlugIn系統
2024-07-21 02:15:48
供稿:網友
 
本文來源于網頁設計愛好者web開發社區http://www.html.org.cn收集整理,歡迎訪問。話說公元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!”的提示框。