こんにちは!開発現場で日々奮闘されている皆さん、順調ですか?
今回は、中級者へのステップアップとして避けて通れない「例外情報(Exception.StackTrace と InnerException)の正しい扱い方」についてお話しします。
実務でシステムを作っていると、「画面でエラーになったけれど、原因がどこにあるのかさっぱり分からない…」という悪夢のような瞬間に出会うことがありますよね。特に、画面・ビジネスロジック・データベースアクセスと層(レイヤー)が分かれたマルチレイヤーアプリでは、エラーの発生源が隠れてしまいがちです。
今回は、先輩エンジニアとして、「エラーを握りつぶさず、正確な足跡を追跡するプロのログ設計」の極意を優しく、そして深く伝授します。ここをクリアすれば、あなたの書くVB.NETコードの信頼性は劇的に跳ね上がりますよ。バッチリマスターしていきましょう!
—
1. なぜ「例外の握りつぶし」は悪なのか?
初学者にありがちなアンチパターンとして、次のようなコードを見かけます。
.net
‘ 【やってはいけない例】エラーを握りつぶす
Try
‘ データベース処理など
Call DoSomething()
Catch ex As Exception
‘ ログを出力するだけで、例外を外に伝えない(または例外オブジェクトを無視する)
MessageBox.Show(“エラーが発生しました。”)
End Try
これの何が問題か分かりますか?
例外(Exception)が発生したこと自体はキャッチできていますが、「どこで」「なぜ」起きたのかという重要なコンテキスト(文脈)が消え去ってしまっているのです。これでは、メンテナンス時にデバッグのしようがありません。
実務の現場では、エラーは適切にキャッチしつつも、「上位のレイヤーへ正確な情報を引き継ぐ(またはログに残す)」ことが鉄則です。
—
2. マルチレイヤーアプリにおける例外の構造
マルチレイヤー(多層)アーキテクチャでは、一般的に次のような構造になっています。
1. プレゼンテーション層(UI / 画面): ユーザーからの入力を受け取り、結果を表示する。
2. ビジネスロジック層(BLL): 業務ルールや計算処理を行う。
3. データアクセス層(DAL): データベースとの通信やSQL実行を行う。
例えば、DB接続エラー(DAL)が起きたとき、それをそのままUI層で「画面が表示できません」と処理してしまうと、DBの接続文字列が間違っているのか、SQL構文がおかしいのかの判がつきません。
ここで重要になるのが、`InnerException`(内部例外)と`StackTrace`(スタックトレース)です。
—
3. 実践! `InnerException` と `StackTrace` を使いこなす
では、具体的なコードを見ていきましょう。
データアクセス層で起きた低レベルな例外を、ビジネスロジック層でラップ(包み直して)し、上位へ伝播させる実務的なサンプルコードです。
.net
Imports System
Imports System.IO
Namespace EnterpriseApp.DataAccess
‘ — データアクセス層 (DAL) —
Public Class UserRepository
Public Sub GetUserData(userId As Integer)
Try
‘ 仮想的なファイル読込エラー(実際はDB接続など)
Throw New FileNotFoundException(“ユーザーマスタファイルが見つかりません。”)
Catch ex As Exception
‘ DAL固有の例外として再スロー(または独自例外でラップする)
Throw New ApplicationException(“データアクセス層でエラーが発生しました。”, ex)
End Try
End Sub
End Class
End Namespace
Namespace EnterpriseApp.BusinessLogic
Imports EnterpriseApp.DataAccess
‘ — ビジネスロジック層 (BLL) —
Public Class UserService
Private _repo As New UserRepository()
Public Sub ProcessUser(userId As Integer)
Try
_repo.GetUserData(userId)
Catch ex As Exception
‘ ★ここがポイント! InnerException を保持したまま上位へ伝える
Throw New InvalidOperationException(“ユーザー処理の実行に失敗しました。”, ex)
End Try
End Sub
End Class
End Namespace
コードの解説:なぜ `ex` を一緒に渡しているのか?
`Throw New InvalidOperationException(“…”, ex)` の部分に注目してください。
ここで第2引数に元の例外(`ex`)を渡しているのが、`InnerException`(内部例外)を設定する処理です。
これを行わないと、DALで起きた本当の原因(ファイルが見つからないこと)が消えてしまい、BLLのエラーメッセージだけになってしまいます。`InnerException` をチェーン(鎖)のように繋いでいくことで、「UI層 → BLL層 → DAL層」のどの段階で何が起きたのかを完璧に辿ることができるのです。
—
4. ログ出力の実装:スタックトレースを味方につける
では、一番上の層(UI層やグローバルエラーハンドラー)で、実際にこの例外情報をどのように取得し、ログに残すべきでしょうか?
以下のコードは、例外の階層を再帰的(またはループ)に辿り、すべてのメッセージとスタックトレースを出力するテクニックです。
.net
Public Module ExceptionLogger
‘ 例外の詳細情報を再帰的に取得してログ出力するメソッド
Public Sub LogException(ex As Exception)
Dim currentEx As Exception = ex
Dim depth As Integer = 1
‘ 内部例外(InnerException)がなくなるまでループする
While currentEx IsNot Nothing
Console.WriteLine($”— [階層 {depth}] —“)
Console.WriteLine($”例外の種類: {currentEx.GetType().FullName}”)
Console.WriteLine($”メッセージ: {currentEx.Message}”)
Console.WriteLine($”スタックトレース:”)
Console.WriteLine(currentEx.StackTrace)
Console.WriteLine(New String(“-“c, 40))
‘ 次の内部例外へシフト
currentEx = currentEx.InnerException
depth += 1
End While
End Sub
End Module
StackTrace(スタックトレース)が教えてくれること
`StackTrace` プロパティには、例外が発生した時点までの「メソッド呼び出しの履歴」が上から順に記録されます。
これを見ることで、「どのクラスの、どのメソッドの、何行目でエラーが起きたのか」が一目瞭然になります。リリースビルドであっても、PDBファイル(デバッグシンボル)が適切に配置されていれば、正確な行番号まで特定可能です。
—
5. 陥りがちな罠と注意点
初心者がやりがちなミスをいくつか挙げておきます。
1. `Exception.ToString()` を過信しない
実は `.ToString()` を呼ぶだけで、メッセージ、例外の型、そしてスタックトレース(InnerExceptionの情報含む)が綺麗に結合されて取得できます。簡易的なログ出力であれば `Console.WriteLine(ex.ToString())` やロガーの `logger.Error(ex)` で十分な場合が多いです。ただし、構造化ログ(JSON等)に出力する際は、個別にプロパティを分解して渡す必要があります。
2. スタックトレースの「巻き戻し(Throw)」に注意
`Catch ex As Exception` の中で、単に `Throw` とだけ書くと、現在のスタックトレースが維持されます。しかし、`Throw ex` と書いてしまうと、スタックトレースがその行でリセットされてしまうため、エラーの発生源が分かりにくくなります。基本は新しい例外で包むか、そのまま `Throw` するようにしましょう。
—
まとめ
今回は、VB.NETにおけるマルチレイヤーアプリでの例外情報取得とログ設計について解説しました。
- 例外を握りつぶさない:必ずキャッチしたら適切に上位へ伝えるか記録する。
- `InnerException` で原因を繋ぐ:層をまたぐときは元の例外をラップして文脈を維持する。
- `StackTrace` で足跡を追う:メソッドの呼び出し履歴からエラーの震源地を正確に特定する。
ここを意識するだけで、トラブルシューティングのスピードが何倍も変わり、「頼れるエンジニア」へと大きく近づきます。ぜひ、実際の開発現場のコードでも意識して取り入れてみてくださいね。
それでは、次回のスキルアップでお会いしましょう!バッチリ使いこなしてくださいね!
