背景をいくつか説明します。定期的にサイトがクラッシュし、IIS を再起動しなければならなくなります。これはほとんどの場合、DLL にパッチを適用してから 1 時間以内に発生します (Web アプリケーション プロジェクトではなく Web サイト プロジェクトを使用するため、各 ASPX ページは個別の DLL です)。
いくつかの調査を行った結果、自作の DAL は、デバッグ中に、ストアド プロシージャで SQL エラーが発生した場合、Visual Studio を備えた組み込み Web サーバーの動作を実際に停止し、シャットダウンする可能性があることを発見しました (つまり、それだけではありません)。ブラウザに表示される例外をスローすると、実際には Web サーバーでエラーが発生したため、閉じる必要があると表示されます!)
さらに掘り下げると、エラーは DAL 内のすべて (Select ステートメントを含む) のトランザクションの使用に関連しているようです。何が起こっているように見えるかは次のとおりです。
- ストアド プロシージャを実行しようとしましたが、列がない/無効である、またはその他のエラーが原因でストアド プロシージャが失敗しました。
- アプリケーション コードはエラーをキャッチして再スローします (悪いことですが、これは私が書いたものではありません)。
- トランザクションは例外にもかかわらずコミットを試み、行
NullReferenceException
上にを取得します (トランザクション オブジェクトがあるため、プロパティ上にあるようです)。また、この NullRef はキャッチできないようです (無効な Sproc で強制的にクラッシュしたデモを試してみましたが、エラーを出力してもその型が.transaction.Commit()
Connection
System.NullReferenceException
- トランザクションは、「トランザクションが完了し、使用できなくなりました」のようなエラーをスローします。
- ??? しかし、VS Web サーバーがクラッシュします。この部分のデバッグは、上記の例外でハングしているようで、メソッドを離れることはありません。
これが IIS のクラッシュの原因かどうかはわかりませんが、かなり疑わしいようで、いずれにしても明らかなエラーです。
以前にトランザクションを扱ったことがなく、それらの基本的な考え方しか持っていなかったので、私の最初の質問は、例外がスローされた後にトランザクションがまだコミットしようとしているのはなぜですか? 私の 2 番目の質問は、コミットの失敗と、おそらくサーバーが停止するまでの例外の無限ループを修正する方法です。次のようなものを追加するのは理にかなっていませんか (メソッドは という名前の SqlTransaction パラメーターを取りますtransaction
):
catch (SqlException se)
{
if (transaction != null)
{
transaction.Rollback();
}
throw;
}
その小さな変更で、IIS をクラッシュさせていると思われる絶え間ない例外ループが修正されるでしょうか? DAL 自体は非常に脆く、何百ものファイルで具体的に使用されているため、最初から正しく書き直すことはできません。
編集コードブロック全体は次のとおりです(これもレガシーコード-古いMicrosoftデータアクセスブロックヘルパーを使用しています):
public static DataSet ExecuteDatasetStoredProc(SqlConnection conn, String storedProcName, SqlTransaction transaction, params SqlParameter[] storedProcParms)
{
try
{
// Execute the stored proc
if (transaction != null)
{
return SqlHelper.ExecuteDataset(transaction, CommandType.StoredProcedure, storedProcName, storedProcParms);
}
else
{
return SqlHelper.ExecuteDataset(conn, CommandType.StoredProcedure, storedProcName, storedProcParms);
}
}
catch (SqlException se)
{
throw new ApplicationException("Error calling " + storedProcName + ". " + se.Message, se);
}
}
ただし、catch ブロックが実行されると、トランザクションは引き続きコミットを試み、これがハングアップの原因になっているようです。