Dealing with corrupt xlsx, docx files when reading from SQL Blob

I've had a bug in my bug tracking system for our CMS for a while now.  Basically, any Office 2007 files that where uploaded into our CMS came back as corrupt when downloaded.  The short term solution was to have everyone down-convert the docs.  I finally got around to fixing this today and wanted to share my results with everyone.

My old code looked like this.
do
{
    bytesRead = dr.GetBytes(11, readFrom, bytes, 0, bufferSize);
    System.Web.HttpContext.Current.Response.BinaryWrite(bytes);
    readFrom += bufferSize;
}
while (bytesRead == bufferSize);

From my research, it looks like this will work fine for most anything but Office 2007 docs, for whatever reason, those tend to end up being a single byte too long.  Of course the other possability is that many things where a single byte too long but their document formats either didn't care or took care of that extra padding.  In any case the solution is to use Response.OutputStream.Write instead of Response.BinaryWrite
Here's the new code:
byte[] buffer = new Byte[4096];
try
{
    long startIndex = 0; //Start of the blob
    Stream outputStream = Context.Response.OutputStream;
    while ((bytesRead = dr.GetBytes(blobColumnIndex, startIndex, buffer, 0, buffer.Length)) > 0)
    {
        // Verify that the client is connected.
        if (System.Web.HttpContext.Current.Response.IsClientConnected)
        {
            outputStream.Write(buffer, 0, (int)bytesRead);

            // Reposition the start index to the end of the last buffer and fill the buffer.
            startIndex += bytesRead;
        }
        else
        {
            //prevent infinite loop if user disconnects
            startIndex += 10000;
        }
    }
}
catch (Exception ex)
{
    // Trap the error, if any.
    System.Web.HttpContext.Current.Response.Write("Error : " + ex.Message);
}
finally
{
    System.Web.HttpContext.Current.Response.Close();
}

Remember that datareader.GetBytes relies on the datareader being in SequentialAccess mode, ala
SqlDataReader dr = cmd.ExecuteReader(CommandBehavior.SequentialAccess);
in SequentialAccess mode you must access the columns in order.

Hope this helps those suffering the same problem.

0 comments:

Post a Comment