如何下载存储在数据库中的大文件..流利的nhibernate
本文关键字:文件 nhibernate 数据库 何下载 下载 存储 | 更新日期: 2023-09-27 18:24:50
使用:C#,.NET 3.5 web表单应用程序,fluent nhibernate 1.1.0.685,SQL Server 2008R2
我有一个网络应用程序,允许用户上传文件,并将其附加到他们正在处理的"案例"中。这些文件以varbinary(MAX)的形式存储在数据库中。
以下是我目前用于下载文件的代码:
...
if (!SiteUserService.HasPermission(Domain.SiteUserService.SitePermissions.ModifyCase, CurrentUser))
this.AccessDenied();
string attachmentId = Request.QueryString["f"].ToString();
DownloadFileResponse response = CaseService.RetrieveAttachment(attachmentId, CurrentUser.Id);
DownloadAttachment(response.Attachment.ContentType, response.Attachment.FileName, response.FileBytes);
...
protected void DownloadAttachment(string mimeType, string fileName, byte[] file)
{
Response.Clear();
Response.ContentType = mimeType;
Response.AddHeader("content-disposition", string.Format("attachment;filename='"{0}'"", fileName));
Response.BinaryWrite(file);
Response.Flush();
Response.End();
}
这适用于较小的文件。昨天上传了几个文件,大小(字节):2230165、2104051、1024274和2202318。当用户尝试下载这些文件时,他们会收到"请求超时"错误。大多数文件的大小约为45572字节。
有问题的应用程序位于DMZ中,因此我们使用WCF服务进行数据访问,没有直接的SQL调用,因此这样的解决方案不起作用。
我在文件系统中没有物理文件,所以我认为下面的代码不起作用:
System.IO.Stream stream = null;
byte[] buffer = new Byte[10000];
int length;
long dataToRead;
string filePath = context.Request.PhysicalPath;
string fileName = System.IO.Path.GetFileName(filePath);
try
{
stream = new System.IO.FileStream(filePath, System.IO.FileMode.Open,
System.IO.FileAccess.Read,System.IO.FileShare.Read);
dataToRead = stream
context.Response.ContentType = "application/octet-stream";
context.Response.AddHeader("Content-Disposition", "attachment; filename=" + fileName);
while(dataToRead > 0)
{
if(context.Response.IsClientConnected)
{
length = stream (buffer, 0, 10000);
context.Response.OutputStream.Write(buffer, 0, length);
context.Response.Flush();
buffer= new Byte[10000];
dataToRead = dataToRead - length;
}
else
{
dataToRead = -1;
}
}
}
catch(Exception ex)
{
throw(ex);
}
finally
{
if(stream != null)
{
stream ();
}
}
关于如何允许文件以"块"形式下载,有什么建议吗?
编辑:我也研究过这个解决方案,但不知道如何用DB中的一个字节[]来实现它。
您必须使用sql server的Streaming api,该api可以封装到Stream中。然后像这个一样使用它
var sqlConn = (SqlConnection)session.Connection;
BlobStream blob = new BlobStream(sqlConn, sqlConn.BeginTransaction(), "dbo", "Uploads", "FileData", "Id", id);
BufferedStream bufferedBlob = new BufferedStream(blob, 8040);
// use bufferedBlob to stream from and to context stream
以下是我最终所做的:
public class DownloadHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
// send the file in 10k chunks -- should help with mem consumption
Stream stream = null;
byte[] buffer = new Byte[10000];
// Length of the file:
int length;
// Total bytes to read:
long dataToRead;
try
{
CaseService svc = new CaseService();
// Retrieve the attachment
DownloadFileResponse response = svc.RetrieveAttachment(context.Request["f"].ToString(), context.Request["u"].ToString());
AttachmentContract file = response.Attachment;
stream = new MemoryStream(response.FileBytes);
// Total bytes to read:
dataToRead = Convert.ToInt64(file.FileSize);
context.Response.ContentType = "application/octet-stream";
context.Response.AddHeader("Content-Disposition", "attachment; filename=" + file.FileName);
// Read the bytes.
while (dataToRead > 0)
{
// Verify that the client is connected.
if (context.Response.IsClientConnected)
{
// Read the data in buffer.
length = stream.Read(buffer, 0, 10000);
// Write the data to the current output stream.
context.Response.OutputStream.Write(buffer, 0, length);
// Flush the data to the HTML output.
context.Response.Flush();
buffer = new Byte[10000];
dataToRead = dataToRead - length;
}
else
{
//prevent infinite loop if user disconnects
dataToRead = -1;
}
}
}
catch (Exception)
{
// Trap the error, if any.
throw;
}
finally
{
if (stream != null)
{
//Close the file.
stream.Close();
}
}
}
public bool IsReusable
{
get
{
return false;
}
}
}
Web.config:
<system.web>
...
<httpRuntime maxRequestLength="51200" />
...
</system.web>
<system.serviceModel>
...
<bindings configSource="Config'Wcf'bindings.config" />
...
</system.serviceModel>
bindings.config:
<binding name="reliableBinding" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:10:00" allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="1048576" maxReceivedMessageSize="4194304" messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="4194304" maxBytesPerRead="51200" maxNameTableCharCount="4194304" />
<reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="true" />
<security mode="None">
<transport clientCredentialType="None" proxyCredentialType="None" realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>