さらに調査した結果、OutOfMemoryExceptionを停止し、予想されるTimeoutExceptionを取得する方法を見つけました。
この場合、ストアドプロシージャでPRINTが使用されているため、メモリが増加しています。Drieverは、デフォルトでデータベースから出力を収集しています。したがって、ユーザーがこれを読み取っていない場合、OutOfMemoryExceptionが発生する可能性があります。
必要な結果に応じて、2つのソリューションを使用できます。
1つ目は、データベース出力が重要ではなく、実行に時間がかかる場合にTimoutを期待している場合に適しています。以下のスニペットは、この方法で問題を解決します。
public void CallProcedure()
{
// Line below release all Errors/PRINT output from command. Command is now
// not collecting them, so memory is not growing.
// CommandTimeout will be thrown after preset value on command object.
this._connection.FireInfoMessageEventOnUserErrors = true;
SqlCommand cmd = this._connection.CreateCommand();
cmd.CommandTimeout = 15;
cmd.CommandType = CommandType.StoredProcedure;
command.CommandText = 'InfiniteLoop';
//Line below throws OutOfMemoryException
cmd.ExecuteNonQuery();
cmd.Dispose();
}
2つ目は、非常に時間がかかる可能性のある非常に時間のかかる手順を実行する場合のグーグです。タイムアウト例外は発生しません。この動作を有効にするには、SqlConnectionのInfoMessageにSqlInfoMessageEventHandlerをアタッチする必要があります。以下のスニペットを参照してください。
public void CallProcedure()
{
// By attaching this event no Timeout exception on ExecuteNonQuery occur
// Your ExecuteNonQuery can hang infinitly!
// If you need Timeout then you need to write you own handler from different thread
this._connection.InfoMessage += new SqlInfoMessageEventHandler(OnInfoMessage);
// Line below release all Errors/PRINT output from command. Command is now
// not collecting them so memory is not growing.
this._connection.FireInfoMessageEventOnUserErrors = true;
SqlCommand cmd = this._connection.CreateCommand();
// In this case Timeout will never occur
cmd.CommandTimeout = 15;
cmd.CommandType = CommandType.StoredProcedure;
command.CommandText = 'InfiniteLoop';
//Line below throws OutOfMemoryException
cmd.ExecuteNonQuery();
cmd.Dispose();
this._connection.InfoMessage -= new SqlInfoMessageEventHandler(OnInfoMessage);
}
void OnInfoMessage(object sender, SqlInfoMessageEventArgs e)
{
System.Diagnostics.Debug.WriteLine(DateTime.Now.ToString()+": "+ e.Message);
}