从SQL数据库读取BLOB对象时文件损坏

时间:2018-07-05 16:02:18

标签: c# asp.net webforms

所有,有人可以提供帮助。

在读取SQL DB中的BLOB对象时遇到问题。正在下载文件,但由于文件损坏而无法打开。任何文档类型(pdf,docx,jpg等)都会出现错误。

代码执行一个存储过程,该存储过程基于两个不同的参数来获取二进制文件。

代码如下:

        protected void Page_Load(object sender, EventArgs e)
    {
        // Request.QueryString["docid"].ToString(); 
        //string DocumentID = Request.QueryString["DocumentID"].ToString();
        string DocumentID = "9163736c-8064-11e8-ab16-2c44fd826130";
        string SessionId = "91494483-8064-11e8-ab16-2c44fd826130";
        //Connection and Parameters
        SqlParameter param1 = null;
        SqlParameter param2 = null;
        SqlConnection conn = new SqlConnection(
           ConfigurationManager.ConnectionStrings["ProcessManagerConnectionString"].ToString());
        SqlCommand cmd = new SqlCommand("sp_getdoc", conn);
        cmd.CommandType = CommandType.StoredProcedure;
        param1 = new SqlParameter("@DocumentID", SqlDbType.NVarChar, 100);
        param2 = new SqlParameter("@SessionId", SqlDbType.NVarChar, 100);
        param1.Direction = ParameterDirection.Input;
        param2.Direction = ParameterDirection.Input;
        param1.Value = DocumentID;
        param2.Value = SessionId;
        cmd.Parameters.Add(param1);
        cmd.Parameters.Add(param2);
        //Open connection and fetch the data with reader
        conn.Open();
        SqlDataReader reader =
          cmd.ExecuteReader(CommandBehavior.CloseConnection);
        if (reader.HasRows)
        {
            reader.Read();
            //
            string doctype = reader["Extension"].ToString();
            string docname = reader["Docname"].ToString();
            //
            Response.Buffer = false;
            Response.ClearHeaders();
            Response.ContentType = doctype;
            Response.AddHeader("Content-Disposition",
                     "attachment; filename=" + docname);
            //
            //Code for streaming the object while writing
            const int ChunkSize = 1024;
            byte[] buffer = new byte[ChunkSize];
            byte[] binary = (reader["Data"]) as byte[];
            MemoryStream ms = new MemoryStream(binary);
            int SizeToWrite = ChunkSize;

            for (int i = 0; i < binary.GetUpperBound(0) - 1; i = i + ChunkSize)
            {
                if (!Response.IsClientConnected) return;
                if (i + ChunkSize >= binary.Length)
                    SizeToWrite = binary.Length - i;
                byte[] chunk = new byte[SizeToWrite];
                ms.Read(chunk, 0, SizeToWrite);
                Response.BinaryWrite(chunk);
                Response.Flush();
            }
            Response.Close();

        }

1 个答案:

答案 0 :(得分:1)

无需在此处进行任何分块。您已经将二进制数据加载到内存中。只需拨打以下电话即可:

Response.BinaryWrite(binary);

避免创建MemoryStream等。我觉得您的分块代码存在错误。

如果您希望减少流二进制数据时应用程序中的内存使用,则应考虑使用CommandBehavior.SequentialAccess

最后,相对于System.Web.IHttpHandler(ASPX),我更喜欢使用简单的System.Web.UI.Page(ASHX)处理这类事情。

尝试创建一个名为HectorsHandler.ashx的文件,其内容如下:

<%@ WebHandler Language="C#" Class="HectorsApp.HectorsHandler" %>

using System;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Web;

namespace HectorsApp
{
    public class HectorsHandler : IHttpHandler
    {
        public void ProcessRequest(HttpContext ctxt)
        {
            // Request.QueryString["docid"].ToString(); 
            //string DocumentID = Request.QueryString["DocumentID"].ToString();
            string DocumentID = "9163736c-8064-11e8-ab16-2c44fd826130";
            string SessionId = "91494483-8064-11e8-ab16-2c44fd826130";
            //Connection and Parameters
            SqlParameter param1 = null;
            SqlParameter param2 = null;
            using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["ProcessManagerConnectionString"].ToString()))
            {
                SqlCommand cmd = new SqlCommand("sp_getdoc", conn);
                cmd.CommandType = CommandType.StoredProcedure;
                param1 = new SqlParameter("@DocumentID", SqlDbType.NVarChar, 100);
                param2 = new SqlParameter("@SessionId", SqlDbType.NVarChar, 100);
                param1.Direction = ParameterDirection.Input;
                param2.Direction = ParameterDirection.Input;
                param1.Value = DocumentID;
                param2.Value = SessionId;
                cmd.Parameters.Add(param1);
                cmd.Parameters.Add(param2);
                //Open connection and fetch the data with reader
                conn.Open();
                using (SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
                {
                    if (reader.Read())
                    {
                        //
                        string doctype = reader["Extension"].ToString();
                        string docname = reader["Docname"].ToString();
                        //
                        ctxt.Response.BufferOutput = false;
                        ctxt.Response.Buffer = false;
                        ctxt.Response.ContentType = doctype;
                        ctxt.Response.AddHeader("Content-Disposition", "attachment; filename=" + docname);

                        //Code for streaming the object while writing
                        byte[] buffer = new byte[8040];
                        long dataIndex = 0;
                        while (ctxt.Response.IsClientConnected)
                        {
                            long bytesRead = reader.GetBytes(reader.GetOrdinal("Data"), dataIndex, buffer, 0, buffer.Length);
                            if (bytesRead == 0)
                            {
                                break;
                            }
                            ctxt.Response.OutputStream.Write(buffer, 0, (int)bytesRead);
                            ctxt.Response.OutputStream.Flush();
                            dataIndex += bytesRead;
                        }
                    }
                }
            }
        }

        public bool IsReusable
        {
            get { return false; }
        }
    }
}

根据下面的注释,您现在可以完全控制输出内容,因此不再需要清除任何数据。

请注意,因为正在使用CommandBehavior.SequentialAccess,所以必须按顺序读取列。

Is there any performance gain from CommandBehavior.SequentialAccess?

相关问题