【转载】基于ASP.NET Web Application的插件实现,附DEMO
??? 使用插件機制來擴展B/S程序,主要需要實現兩個功能,首先是動態編譯插件中的C#代碼,然后利用反射來執行插件已經編譯的C#代碼。
???
??? 一、動態編譯
??? 插件一般是以xml文件的形式實現其配置,必須要先讀取插件中的C#代碼才能進行動態編譯。
XmlDocument?doc?=?new?XmlDocument();?try?
{?
????//獲取插件配置文件?
????doc.Load(Server.MapPath(@"plugins/"?+?strPluginName?+?"/config.xml"));?
}?
catch?(Exception?e)?
{?
????Response.Write("插件載入錯誤:"?+?e.ToString());?
????return;?
}?
XmlNode?xn?=?doc.DocumentElement.SelectSingleNode("csharpcode");?
string?code?=?string.Empty;?
if?(xn?!=?null)?
{?
????XmlElement?xe?=?(XmlElement)xn;?
????if?(xe.HasAttribute("link"))?
????{?
XmlDocument?doc?=?new?XmlDocument();?
try?
{?
????//獲取插件配置文件?
????doc.Load(Server.MapPath(@"plugins/"?+?strPluginName?+?"/config.xml"));?
}?
catch?(Exception?e)?
{?
????Response.Write("插件載入錯誤:"?+?e.ToString());?
????return;?
}?
XmlNode?xn?=?doc.DocumentElement.SelectSingleNode("csharpcode");?
string?code?=?string.Empty;?
if?(xn?!=?null)?
{?
????XmlElement?xe?=?(XmlElement)xn;?
????if?(xe.HasAttribute("link"))?
????{?
using?(?
????????????StreamReader?sr?=?
????????????????System.IO.File.OpenText(?
????????????????????Path.Combine(?
????????????????????????Server.MapPath(@"plugins/"?+?strPluginName?+?"/"),?xe.GetAttribute("link")?
????????????????????)?
????????????????)?
?????????)?
????????{?
????????????code?=?sr.ReadToEnd();?
????????????sr.Close();?
????????}?
????}?
????else?
????{?
????????code?=?xe.InnerText;?
????}?
} 復制代碼
?
?.Net為我們提供了很強大的支持來實現這一切我們可以去做的基礎,主要應用的兩個命名空間是:System.CodeDom.Compiler和Microsoft.CSharp或Microsoft.VisualBasic。另外還需要用到反射來動態執行你的代碼。動態編譯并執行代碼的原理其實在于將提供的源代碼交予CSharpCodeProvider來執行編譯(其實和CSC沒什么兩樣),如果沒有任何編譯錯誤,生成的IL代碼會被編譯成DLL存放于于內存并加載在某個應用程序域(默認為當前)內并通過反射的方式來調用其某個方法或者觸發某個事件等。之所以說它是插件編寫的一種方式也正是因為與此,我們可以通過預先定義好的借口來組織和擴展我們的程序并將其交還給主程序去觸發。一個基本的動態編譯并執行代碼的步驟包括:
將要被編譯和執行的代碼讀入并以字符串方式保存
聲明CSharpCodeProvider對象實例
調用CSharpCodeProvider實例的CompileAssemblyFromSource方法編譯
用反射生成被生成對象的實例(Assembly.CreateInstance
調用其方法
以下代碼片段包含了完整的編譯和執行過程:
CodeSnippetCompileUnit?unit?=?new?CodeSnippetCompileUnit(code);?ICodeCompiler?compiler?=?new?CSharpCodeProvider().CreateCompiler();?
CompilerParameters?para?=?new?CompilerParameters();?
para.ReferencedAssemblies.Add("System.dll");?
para.ReferencedAssemblies.Add("System.Data.dll");?
para.ReferencedAssemblies.Add("System.XML.dll");?
para.ReferencedAssemblies.Add("System.Drawing.dll");?
para.ReferencedAssemblies.Add("System.Web.dll");?
para.ReferencedAssemblies.Add(Server.MapPath(this.Request.ApplicationPath?+?"/bin/PluginDemo.dll"));?
para.GenerateExecutable?=?false;?
para.OutputAssembly?=?dllPath;?
?
//編譯結果?
CompilerResults?cr?=?compiler.CompileAssemblyFromDom(para,?unit);?
if?(cr.Errors.Count?>?0)?
{?
????Response.Write("插件安裝失敗,編譯錯誤:<br/>");?
????//遍歷編譯錯誤?
????foreach?(System.CodeDom.Compiler.CompilerError?ce?in?cr.Errors)?
????{?
????????Response.Write(ce.ErrorText?+?"(文件:"?+?ce.FileName?+?",行號:"?+?ce.Line.ToString()?+?",錯誤編號:"?+?ce.ErrorNumber?+?")<br/>");?
????}?
????return;?
} 復制代碼
???? 了解更多的關于動態編譯的知識
這里引用了? System.CodeDom和System.CodeDom.Compiler。
讀取插件中的C#代碼并進行動態編譯后,要實現插件功能,就需要執行已經編譯好的插件的dll中的代碼了。
??? 二、利用反射實現插件功能
??? 反射的原理這里就不再說了,三層架構中用的太多了,呵呵。
public?string?GetPluginOutPut(string?strPluginName)?{?
????try?
????{?
????????//載入插件程序集?
????????System.Xml.XmlDocument?doc?=?new?System.Xml.XmlDocument();?
????????doc.Load(Server.MapPath("plugins/installedplugins.xml"));?
?
????????string?asmName?=?((System.Xml.XmlElement)doc.DocumentElement.SelectSingleNode("plugin[@name='"?+?strPluginName?+?"']")).GetAttribute("assembly");?
?
????????System.Reflection.Assembly?asm?=?System.Reflection.Assembly.LoadFrom(Server.MapPath(@"plugins/bin/"?+?asmName));?
????????IPlugin?plugin?=?(IPlugin)asm.CreateInstance("PluginDemo.plugins."?+?strPluginName);?
?
????????return?plugin.GetOutput(this);?
????}?
????catch?(Exception?ex)?
????{?
????????return?"插件‘"?+?strPluginName?+?"’載入失敗:"?+?ex.ToString();?
????}?
} 復制代碼
?
?忘了說一下,要實現反射,我們需要先在網站中定義好的一個IPlugin接口
/**////?<summary>?///?插件接口?
///?</summary>?
public?interface?IPlugin?
{?
????/**////?<summary>?
????///?獲取插件輸出的內容?
????///?</summary>?
????///?<param?name="page">System.Web.UI.Page</param>?
????///?<returns>字符串</returns>?
????string?GetOutput(Page?page);?
?
????/**////?<summary>?
????///?安裝插件時執行的代碼?
????///?</summary>?
????///?<param?name="page">System.Web.UI.Page</param>?
????void?Install(Page?page);?
?
????/**////?<summary>?
????///?卸載插件時執行的代碼?
????///?</summary>?
????///?<param?name="page">System.Web.UI.Page</param>?
????void?Uninstall(Page?page);?
?
????/**////?<summary>?
????///?更新插件時執行的代碼?
????///?</summary>?
????///?<param?name="page">System.Web.UI.Page</param>?
????void?Update(Page?page);?
} 復制代碼
?
?
然后所有的插件的C#代碼都繼承自這一個接口。
還是把我做的DEMO發上來吧,講的不好,大家還是看源碼吧,里面都有注釋,呵呵。
下載地址:http://www.box.net/shared/a2ceqq67ts?
總結
以上是生活随笔為你收集整理的【转载】基于ASP.NET Web Application的插件实现,附DEMO的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: oracle-25031安装错误分析解决
- 下一篇: 深入浅出之Smarty模板引擎工作机制(