所有,有人可以提供帮助。
在读取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();
}
答案 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?