C# 如何从ExecuteReader内部解决正在关闭的SqlConnection?
我有一个openC# 如何从ExecuteReader内部解决正在关闭的SqlConnection?,c#,.net,sql-server-2005,C#,.net,Sql Server 2005,我有一个openSqlConnection,代码如下: using (var transaction = connection.BeginTransaction()) { using (var command = connection.CreateCommand()) { command.Transaction = transaction; command.CommandText = "MyQueryText"; using( var reader = c
SqlConnection
,代码如下:
using (var transaction = connection.BeginTransaction()) {
using (var command = connection.CreateCommand()) {
command.Transaction = transaction;
command.CommandText = "MyQueryText";
using( var reader = command.ExecuteReader() ) {
//read data
}
}
}
订阅了SqlConnection.StateChange
event,现在我发现在某个时候,该事件是通过以下堆栈调用的(状态从Open
更改为Closed
):
因此,运行时遇到一些随机错误(我猜是网络连接问题),关闭连接,然后将一个关闭的读卡器对象返回给我的代码,我尝试使用返回的读卡器时产生invalidooperationexception
我需要设法解决这个问题。显然,随机网络错误会发生。我的代码中有重试逻辑,可以处理在网络问题上抛出的SqlException
s,但这里我面对的是一个关闭的读卡器,然后是invalidooperationexception
我的第一个想法是编写我自己的ExecuteReader()
,调用nativeExecuteReader()
,检查是否返回了一个已关闭的读取器,如果出现这种情况,抛出一个新的ClosedReaderReturnedException
,我还将更改重试代码,以便它也对此类异常做出反应,并重新运行查询
我的解决方案好吗?有更好的解决方案吗?基于任何异常(而不是特定的SqlException)的重试逻辑是否存在任何问题?我假设由于编程错误导致的异常最终会在测试阶段被发现,严重的(比如)异常无论如何都不会被catch块捕获,所以用于重试逻辑的通用异常块是可以接受的
如果不是,那么包装
ExecuteReader
的解决方案可能是个好主意。考虑到这是一种行为,您还需要注意ExecuteReader方法可能引发的其他异常-因此您可能需要预测IOException
和ObjectDisposedException
,除了InvalidOperationException
之外,还要在connect网站上提交一个bug。如果你在比赛中抛球会发生什么?你的异常会备份到execute reader吗?@AbdElRaheim:我会提交一个bug,但修复它需要很长时间,或者他们甚至会“按设计”关闭它,我现在需要一个解决方法。这是不可靠的复制,所以我不能真正测试它彻底。有可能检查连接状态后,你调用executereader?也许可以创建一个扩展方法,在命令上调用executereader,然后检查连接状态。也可能是read()的一个方法,它也可以执行相同的操作check@AbdElRaheim:这差不多就是我的建议,不是吗?哦。这是一个很好的解决方案:)重试任何异常都是一个坏主意——它会引发对外部服务的毁灭性请求风暴,并使一切瘫痪。
at MyHandler.onStateChange(Object sender, StateChangeEventArgs e)
at System.Data.ProviderBase.DbConnectionInternal.CloseConnection(DbConnection owningObject, DbConnectionFactory connectionFactory)
at System.Data.SqlClient.SqlConnection.Close()
at System.Data.SqlClient.SqlInternalConnectionTds.BreakConnection()
at System.Data.SqlClient.TdsParserStateObject.ReadSniError(TdsParserStateObject stateObj, UInt32 error)
at System.Data.SqlClient.TdsParserStateObject.ReadSni(DbAsyncResult asyncResult, TdsParserStateObject stateObj)
at System.Data.SqlClient.TdsParserStateObject.ReadNetworkPacket()
at System.Data.SqlClient.TdsParserStateObject.ReadByte()
at System.Data.SqlClient.SqlDataReader.SetMetaData(_SqlMetaDataSet metaData, Boolean moreInfo)
at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
at System.Data.SqlClient.SqlDataReader.ConsumeMetaData()
at System.Data.SqlClient.SqlDataReader.get_MetaData()
at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async)
at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result)
at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method)
at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method)
at System.Data.SqlClient.SqlCommand.ExecuteReader()
// my code calling `ExecuteReader()`