Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Timeout exception causes SqlDataReader to close?

I'm trying to pull some binary data from a database and write them to pdf files. For the most part, this is going along swimmingly, but the occasional row of data seems to throw a particular error -

Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding.

Keep in mind, this only happens on a handful of rows, and is never random. The same rows always throw the exception. I'm not really sure why the exception is being thrown, but I'm ok with skipping the rows that do cause problems and move on. My problem, however, is that when I catch the exception and then try to move onto the next row, I run into another exception -

InvalidOperationException - Invalid attempt to call Read when reader is closed.

Does this mean the reader is automatically closing as soon as it runs into an exception? How would I go about proceeding to the next row without any dramas?

        while (sdrReader.Read()) // Second exception happens here
        {
            try
            {
                byte[] byteData = new Byte[(sdrReader.GetBytes(0, 0, null, 0, int.MaxValue))]; // first exception happens here
                sdrReader.GetBytes(0, 0, byteData, 0, byteData.Length);
                string strOutputFileName = sdrReader.GetInt32(1).ToString() + ".pdf";
                msMemoryStreams = new MemoryStream();
                msMemoryStreams.Write(byteData, 0, byteData.Length);
                byte[] byteArray = msMemoryStreams.ToArray();

                msMemoryStreams.Flush();
                msMemoryStreams.Close();

                writeByteArrayToFile(byteData, txtFilesPath.Text + "\\" + strOutputFileName);
            }
            catch (Exception e)
            {
                Logger.Write("Document failed to convert: " + e.Message);
            }
        }

Stack trace, as requested -

   at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj)
   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.ReadBuffer()
   at System.Data.SqlClient.TdsParserStateObject.ReadByteArray(Byte[] buff, Int32 offset, Int32 len)
   at System.Data.SqlClient.TdsParser.ReadSqlValue(SqlBuffer value, SqlMetaDataPriv md, Int32 length, TdsParserStateObject stateObj)
   at System.Data.SqlClient.SqlDataReader.ReadColumnData()
   at System.Data.SqlClient.SqlDataReader.ReadColumn(Int32 i, Boolean setTimeout)
   at System.Data.SqlClient.SqlDataReader.GetSqlBinary(Int32 i)
   at System.Data.SqlClient.SqlDataReader.GetBytesInternal(Int32 i, Int64 dataIndex, Byte[] buffer, Int32 bufferIndex, Int32 length)
   at System.Data.SqlClient.SqlDataReader.GetBytes(Int32 i, Int64 dataIndex, Byte[] buffer, Int32 bufferIndex, Int32 length)
   at Pdf2Rtf.Form1.Read() in F:\Code\Pdf2Rtf\Pdf2Rtf\Pdf2Rtf\Form1.cs:line 77
   at Pdf2Rtf.Form1.btnRead_Click(Object sender, EventArgs e) in F:\Code\Pdf2Rtf\Pdf2Rtf\Pdf2Rtf\Form1.cs:line 24
   at System.Windows.Forms.Control.OnClick(EventArgs e)
   at System.Windows.Forms.Button.OnClick(EventArgs e)
   at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
   at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.ButtonBase.WndProc(Message& m)
   at System.Windows.Forms.Button.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
   at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
   at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
   at System.Windows.Forms.Application.Run(Form mainForm)
   at Pdf2Rtf.Program.Main() in F:\Code\Pdf2Rtf\Pdf2Rtf\Pdf2Rtf\Program.cs:line 18
   at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
   at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
   at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
   at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ThreadHelper.ThreadStart()
like image 403
Paulie Avatar asked Nov 12 '09 01:11

Paulie


2 Answers

It looks like your SqlCommand is timing out - when you call ExecuteReader, the associated command remains open and will be vulnerable to timeouts until you finish reading. As it says in the SqlCommand.CommandTimeout documentation:

This property is the cumulative time-out for all network reads during command execution or processing of the results. A time-out can still occur after the first row is returned, and does not include user processing time, only network read time.

When the command times out, it closes the reader, from which you can't recover.

The first thing to try to solve this is to increase the CommandTimeout dramatically, just to make sure you can proceed.

Next, if you haven't done so already, it may help to use the ExecuteReader overload that allows you to specify a CommandBehavior, and pass CommandBehavior.SequentialAccess (per the recommendation in the MSDN topic "Retrieving Large Data (ADO.NET)").

Finally, you might also try breaking the reads into chunks of records.

like image 137
Jeff Sternal Avatar answered Oct 01 '22 12:10

Jeff Sternal


If the SQL Error Severity is less than 17, you can set SqlConnection.FireInfoMessageEventOnUserErrors = true to handle the exception as a warning. Anything greater than Severity 17 is going to close the connection no matter what.

like image 22
GuyBehindtheGuy Avatar answered Oct 01 '22 12:10

GuyBehindtheGuy