デバッグビルドでのデバッグ
デバッグビルドを使用するときは、Visual Studioデバッガのすべてのリソース、すべての.NET Framework名前空間、およびすべてのユーティリティとアプリケーションを利用できます。Visual Studioデバッガでは、コールスタック、ローカル変数、ウォッチ変数などを確認できます。読者の皆さんは、これらの機能にある程度は精通していることでしょう。しかし、HTTPハンドラの場合、デバッグはこれまで以上に重要です。それは、目に見える形で現れるバグは、すべてコンテンツにコーディングした内容であるためです。
リリースビルドでのデバッグ
リリースビルドは、機能とパフォーマンスの両方の面でデバッグビルドとは異なります。リリースビルドを使用しているときは、おそらく運用環境にあります。そのような場合は、異なるツールセットを使用して問題箇所を見つける必要があります。
System.Diagnostics名前空間によるデバッグ
Diagnostics名前空間には、リリースモードとデバッグモードでのデバッグに役立つクラスが数多く用意されています。リリースモードでデバッグする場合は、Traceクラスを使用します。デバッグモードでデバッグする場合は、Assertクラスを使用します。本稿では、この名前空間のすべての機能を取り上げるわけではありませんので、当面の問題解決に役立つクラスは各自で調べてください。
これらのクラスの使い方を理解するために、この名前空間を使用して、無限ループを使用するようにコードを変更してみましょう。アサーション内の式がfalseのときにエラーがスローされるので、以下の例ではカウンタが10に達するとエラーがスローされます。
<%@ WebHandler Language="C#" Class="Handler" %> using System; using System.Web; using System.Web.SessionState; using System.Diagnostics; public class Handler : IHttpHandler , IReadOnlySessionState{ public void ProcessRequest (HttpContext context) { context.Response.ContentType = "text/html"; context.Response.Write("Hello World"); int i=0; while (1!=0) { Debug.Assert(i<10); i++; } } public bool IsReusable { get { return false; } } }
ビルドとデバッグを行ってみましょう。ブレークポイントが設定されていないため、アサーションがヒットするとデバッガが再びアクティブになります。発見しようとするエラーがあらかじめ分かっていて、それをテストできる場合には、この方法が適しています。まずアサーションウィンドウが表示され、アサーションに関する情報が表示されます。デバッガをアクティブにしたい場合は、[Retry]ボタンをクリックします。これによりデバッガが表示され、問題のアサーションコード行が示されます。
特定のBoolean文でテストするのではなく、おおまかなコード位置を調べたい場合は、コード内でDebugger.Break文を使用します。この場合も、デバッガが表示されます。前提条件を調べ、なおかつエラーで停止する場合は、この2つの文を組み合わせることで、デバッグのプロセスを効率化することができます。このコードの例を以下に示します。
<%@ WebHandler Language="C#" Class="Handler" %> using System; using System.Web; using System.Web.SessionState; using System.Diagnostics; public class Handler : IHttpHandler , IReadOnlySessionState{ public void ProcessRequest (HttpContext context) { context.Response.ContentType = "text/html"; context.Response.Write("Hello World"); Debugger.Break(); int i=0; while (1!=0) { Debug.Assert(i<10); i++; } } public bool IsReusable { get { return false; } } }
デバッグセッションの中で、Debug.Write、Debug.WriteIf、Debug.WriteLine、およびDebug.WriteLineIfを使用すると、出力ウィンドウに値を書き出すことができます。これは、HTTPハンドラの状態を表示するのに役立ちます。
リリースビルドで問題の原因を突き止めるには、コードを調べる手段が必要です。1つの方法は、コードにEventLog.WriteEntry文を追加することです。これによって、HTTPハンドラの実行時にイベントログに情報を追加することができます。WriteEntryメソッドは非常に負荷がかかるため、各自の環境に適した最善の方法を判断する必要があります。イベントビューアに単純な情報エントリが表示されるようにするには、WriteEntryメソッドに1つのString引数を指定します。イベントビューアはイベントの「ソース」についての情報を要求するので、これを「HTTPHandler-DebugArticle」と名付けます。これにより、イベントビューアで簡単に確認できるようになります。コードは次のようになります。
<%@ WebHandler Language="C#" Class="Handler" %> using System; using System.Web; using System.Web.SessionState; using System.Diagnostics; public class Handler : IHttpHandler , IReadOnlySessionState{ public void ProcessRequest (HttpContext context) { context.Response.ContentType = "text/html"; context.Response.Write("Hello World"); int i=0; // Create an EventLog instance and assign its source. EventLog myLog = new EventLog(); myLog.Source = "HTTPHandler-DebugArticle"; while (i<100) { if (i/10==0) { // Write an informational entry to the event log. myLog.WriteEntry("Writing to event log: i is divisible by 10."); } i++; } } public bool IsReusable { get { return false; } } }
ハンドラのリリースバージョンをビルドし、実際に呼び出してみましょう。出力には、「Hello World」というテキストだけが含まれます。それではイベントビューアを開き、アプリケーションログを開いてください。「HTTPHandler-DebugArticle」というソースからの多くの情報が表示されます。

このうちいずれかのイベントを開くと、簡単な出力が表示されます。

System.Diagnostics名前空間には、パフォーマンスモニタと連携するクラスや、ロジックフローのデバッグに役立つプロセスやクラスもあります。
プロセスにアタッチして実行中のHTTPハンドラをデバッグする
問題箇所を見つけるもう1つの方法として、HTTPハンドラを含むプロセスにアタッチする方法があります。複数のWebサイトを実行していて、各Webサイトがそれぞれ独自のプロセス空間にある場合は、プロセスIDを判別しなければならない可能性があります。ハンドラにこれを指定させるのが、最も簡単な方法です。System.Diagnostics名前空間にはProcessというクラスがあり、現在のプロセスIDを判断するのに役立ちます。IDを見つけるには、コードを次のように変更することで、イベントビューアにIDを送ります。
<%@ WebHandler Language="C#" Class="Handler" %> using System; using System.Web; using System.Web.SessionState; using System.Diagnostics; public class Handler : IHttpHandler , IReadOnlySessionState{ public void ProcessRequest (HttpContext context) { context.Response.ContentType = "text/html"; context.Response.Write("Hello World"); int i=0; Process.GetCurrentProcess().Id.ToString(); // Create an EventLog instance and assign its source. EventLog myLog = new EventLog(); myLog.Source = "HTTPHandler-DebugArticle"; myLog.WriteEntry("Process Id is " + Process.GetCurrentProcess().Id.ToString()); while (i<100) { if (i/10==0) { // Write an informational entry to the event log. myLog.WriteEntry("Writing to event log: i is divisible by 10."); } i++; } } public bool IsReusable { get { return false; } } }
ここで重要なコード行は、ループ内のコード行と、myLog.WriteEntry:Process.GetCurrentProcess().Id内の文字列を置き換えるコード行です。次の図は、イベントビューアのエントリの例を示しています。

プロセスIDが分かったら、このIDをタスクマネージャで探す必要があります。タスクマネージャでプロセスIDを探すには、[プロセス]タブをクリックし、[表示]をクリックして、[列の選択]を選択します。[PID(プロセスID)]チェックボックスをオンにし、[OK]をクリックしてダイアログを閉じます。プロセスのリストに[PID]列が表示されるので、列名をクリックしてソートできます。リスト内で目的のプロセスIDを見つけたら、これを右クリックし、[デバッグ]を選択します。これによってVisual Studioが開始します。Visual Studioからコードファイルを開き、そこでデバッグを行います。
まとめ
ASP.NET HTTPハンドラは単純なクラスであり、これを使用することで要求を処理し、ブラウザに応答を返すことができます。ハンドラによって、現在のWebコンテキストとセッションステートにアクセスできます。Visual Studio 2005で提供される既定の「Generic Handler」は、現在のコードでは動作しない可能性があります。いくつかの変更を加え、System.Diagnostics空間と連携することで、ビルドとデバッグが正しく行われるHTTPハンドラを作成することができます。
