當有問題發生時,它們往往並不是在實驗的時候發生的,機器有輕松調試的 工具。在很多實際情況中,你不好修正的問題總是發生在用戶的機器上,那裡沒 有調試環境,也沒有好的方法計算出問題的情況。在實際情況中,有經驗的開發 人員會創建一個方法,讓系統在運行時捕獲盡可能多的信息。.Net框架已經包含 一些類集合,利用這些集合,你可以做一些通用的調試。而且這些類可以在運行 時或者編譯時進行配置。如果你利用它們,你就可以輕松的發現在實際運行時的 問題。使用框架裡已經存在的代碼,你可以發送一條診斷信息到一個文件,或者 到調試終端。另外,你還可以為你的產品指定特殊的調試輸出級別。你應該盡快 的在你的開發環境中使用這些功能,以確保你可以利用這些輸出信息來修正在實 際運行中沒有預料到的一些問題。不要自己寫診斷庫除非你已經明白框架已經提 供了哪些。
System.Diagnostics.Debug, System.Diagnostics.Trace和 System.Diagnostics.EventLog類提供了你在運行程序時要創建診斷信息的所有 工具。前面兩個類功能是基本上是一樣的。不同之外是Trace類是由預處理符 TRACE控制的,而Debug類則是由DEBUG預處理符控制的。當你用VS.net開發一個 項目時,TRACE符號是同時在調試版和發布版中定義的。你可以為所有的發布版 使用Trace類來創建診斷信息。EventLog類提供了一個入口,通過這個入口,你 的程序可以寫一些系統日志。EventLog類不支持運行時配置,但你可以把它封裝 到一個統一的簡單接口中。
你可以在運行時控制診斷輸出,.Net框架使 用一個應用程序配置文件來控制變化多樣的運行時設置。這個是一個XML文件,在主應用程序運行時的目錄中。這個文件與應用程序同名,但添加了一 個.config後綴。務更制塊例如MyApplication.exe 可能會有一個 MyApplication.exe.config的XML文件來控制它。所所有的配置信息包含在一個 configuration節點中:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
</configuration>
.Net框架使用預定義的關鍵字來控制 框架中一些類的行為。另外,你可以定義你自己的配置關鍵字和值。
你 可以組合輸出開關和Trace.WriteLineIf()方法來控制應用程序的輸出。你可以 在應用程序外以默認的方式關閉這個輸出,以便應用程序得到最好的性能。當發 現問題時,你可以打開這個輸出用於診斷和修正在實際中遇到的問題。 WriteLineIf()只有在表達式為真時才輸出:
bool _printDiagnostics = true;
Trace.WriteLineIf( _printDiagnostics,
"Printing Diagnostics Today", "MySubSystem" );
你所創建的輸出開關用於控制輸出 的級別,一個輸出開關可以是由應用程序配置文件定義的變量,可以是五種狀態 之一:關閉(Off),錯誤(Error),警告(Warning),信息(Info)和詳細(Verbose) 。這些狀態是環境的一部份,而且它們的值可以是從0到4。這樣你就可能為所有 的子系統信息創建一個控制。定義一個輸出開關類然後初始化它就可以創建一個 開關了:
static private TraceSwitch librarySwitch = new
TraceSwitch( "MyAssembly",
"The switch for this assembly" );
第一個參數是開關顯示的名字,第二個 參數是描述。這樣,在運行時可以在應用程序配置文件中配置它們的值。下面就 把librarySwitch設置成Info:
<system.diagnostics>
<switches>
<add name="MyAssembly" value="3" />
</switches>
</system.diagnostics>
如果你編輯了這個配置文件中 開關的值,那麼就修改了所有由那個開關控制的輸出語句。
另一個任務 :你須要配置你的輸出到什麼地方去。 默認是一個鏈接到Trace類上的監聽者: 一個DefaultTraceListener對象。DefaultTraceListener發送信息到調試器,而 且在它的失敗方法(斷言失敗時調用)會打印一些診斷信息然後終止程序。在產品 發布環境中,你不可能看到這樣的信息。但你可是以配置不同的監聽對象到產品 發布環境中:那就是在應用程序的配置文件中添加監聽者。下面就添加了一個 TextWriterTraceListener 到應用程序中:
<system.diagnostics>
<trace autoflush="true" indentsize="0">
<listeners>
<add name="MyListener"
type="System.Diagnostics.TextWriterTraceListener"
initializeData="MyListener.log"/>
</listeners>
</trace>
</system.diagnostics>
TextWriterTraceListener把所 有的診斷信息到打印到一個MyListener.log文件中。名字屬性指定了監聽者的名 字,類型指定了作者監聽對象的類型,它必須是從 System.Diagnostics.TraceListener派生下來的。只有在極少數情況下你才創建 自己的監聽類,那就是你覺得.Net框架的監聽類不夠用。initializeData的值是 一個字符串,用於傳給對象的構造函數。而TextWriterTraceListeners把它用於 文件名。
你可以小做一個擴展,讓它可以在應用中每個部署的程序集上 都可以簡單的使用。對於每個程序集,添加一個類來跟蹤程序集創建的診斷:
internal class MyAssemblyDiagnostics
{
static private TraceSwitch myAssemblySwitch =
new TraceSwitch( "MyAssembly",
"The switch for this assembly" );
internal static void Msg( TraceLevel l, object o )
{
Trace.WriteLineIf( myAssemblySwitch.Level >= l,
o, "MyAssembly" );
}
internal static void Msg( TraceLevel l, string s )
{
Trace.WriteLineIf( myAssemblySwitch.Level >= l,
s, "MyAssembly" );
}
// Add additional output methods to suit.
}
MyAssemblyDiagnostices類根據一個 開關來為這個程序集創建診斷信息。為了創建信息,調用按常規調用重載的Msg 的任何一個就行了:
public void Method1( )
{
MyAssemblyDiagnostics.Msg( TraceLevel.Info,
"Entering Method1." );
bool rVal = DoMoreWork( );
if( rVal == false )
{
MyAssemblyDiagnostics.Msg( TraceLevel.Warning,
"DoMoreWork Failed in Method1" );
}
MyAssemblyDiagnostics.Msg( TraceLevel.Info,
"Exiting Method1." );
}
利用一個全局的開關,你還可以組件特殊的程序集開關,來控制 整個應用程序的輸出:
internal static void Msg( TraceLevel l, object o )
{
Trace.WriteLineIf ( librarySwitch.Level >= l ||
globalSwitch.Level >= l,
o, "MyLibrary" );
}
internal static void Msg( TraceLevel l, string s )
{
Trace.WriteLineIf( librarySwitch.Level >= l ||
globalSwitch.Level >= l,
s, "MyLibrary" );
}
這樣,你就可以在 應用程序上診斷信息,而且更友好的控制個別庫文件的輸出。在應用程序的任何 地方,你都可以設置應用程序級的診斷到錯誤級,從而發現錯誤。當你有一個獨 立的問題時,你可以通過提高這個庫的輸出級別,從而精確的發現問題的源頭。
在實際環境中,對於已經布署的應用程序,診斷庫對於程序診斷和維護 是必須的。但你自己不必寫這些診斷庫:.Net FCL已經完成了核心的功能。盡可 能完全的使用它們,然後在滿足特殊要求時擴展它們。這樣,即使是在產品發布 的環境中也可以捕獲所有的問題。
返回教程目錄