在ASP.NET應用程序運行過程中,很可能會遇到各種意料之外的問題。如果在開發環境下,我們可以設 置斷點,對程序狀態一探究竟。但是很顯然,在產品環境中我們幾乎無法使用這樣的狀態。也正因為如此 ,Dump一個內存快照並進行分析才成為一種“高級技術”,同時在線調試也成為一種需要結合技術能力、 分析能力,甚至抗壓能力的工作。對於調試和解決問題的探索永遠不會停止,各成熟的技術團隊幾乎都會 有一個豐富工具箱,用於應付生產環境中的各種狀況。
在維護一些生產環境中的ASP.NET應用程序時,老趙也經常會感到“力不從心”。雖然我們可以建立豐 富有效的監控或日志等維護機制,但是調試和分析一次程序經常需要耗費大量的腦細胞。因為我們可以使 用的工具大都非常抽象,即使是一個非常微小的問題,也要用較多的時間才能發現“哦,原來是這個變量 的值進入了一種奇怪的狀態”。如果我們有一種機制,可以直觀地檢查生產環境中正在運行的程序的狀態 ,那麼一定可以大大方便我們的工作。
這篇文章記錄的便是老趙的一次探索。
我們的目的是“在程序運行過程中記錄狀態”。使用ASP.NET的傳統機制,例如HttpModule,Trace, 往往需要修改配置和部署新的程序集,這樣一不小心便會造成應用程序的重啟。對於訪問量數據量到了一 定規模的時候,冷啟動的消耗也是相當可觀的,不斷地冷啟動會對應用程序造成非常大的影響。可能我們 希望的,只是能夠簡單地(在不影響現有系統的情況下)執行一段代碼,並輸出一些內容。要實現這點其 實並不難,例如最直接的做法便是提交一段代碼,保存成文件,調用CSC將其編譯成dll,然後在程序中進 行加載。這已經不是一種新鮮的技巧了,它已經用在很多地方,得到了一些不錯的效果。
但是,老趙在這裡還是想使用IronPython,一個原因是老趙最近也在嘗試合理地混用各種語言(F#, IronPython, IronRuby, etc.)編寫應用程序以提高生產力,便“順便”地用上了IronPython的現有成果 。IronPython已經內置了Python代碼的執行引擎,並且能與.NET程序無縫集成。此外,社區中也已經接受 了如Crack.NET等基於IronPython的調試工具1,表明IronPython已經足夠成熟,可以放心使 用。關於更多IronPython的信息,可以參考在QCon London 20092中,《IronPython in Action》一書的作者Michael Foord的演講“Real World IronPython”。
在這裡,我們先准備一個簡單的aspx頁面,其中有兩個文本框,以及一個按鈕:
<asp:TextBox ID="txtCode" runat="server" Height="320px" TextMode="MultiLine"
Width="640px"></asp:TextBox>
<br />
<asp:Button ID="btnExecute" runat="server" onclick="btnExecute_Click"
Text="Execute" />
<br />
<asp:TextBox ID="txtOutput" runat="server" Height="320px" TextMode="MultiLine"
Width="640px"></asp:TextBox>
這裡,我們希望在點擊按鈕之後,可以執行txtCode中的IronPython代碼,並且將信息顯示在 txtOutput中:
protected void btnExecute_Click(object sender, EventArgs e)
{
ScriptEngine engine = Python.CreateEngine();
var scope = engine.CreateScope ();
var script = engine.CreateScriptSourceFromString(
this.txtCode.Text, SourceCodeKind.Statements);
script.Execute(scope);
TextWriter writer = new StringWriter();
scope.SetVariable("logger", writer);
Action<HttpContext> trace;
if (scope.TryGetVariable<Action<HttpContext>>("trace", out trace))
{
trace(this.Context);
}
this.txtOutput.Text = writer.ToString ();
}