0

使用: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 ();
    }
}

关于如何允许以“块”下载文件的任何建议?

编辑:我也查看了这个解决方案,但不知道如何仅使用数据库中的 byte[] 来实现它。

4

2 回答 2

0

您必须使用可以包装成 Stream的 sql server 的 Streaming api 。然后像这样使用它

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
于 2013-08-01T09:19:52.357 回答
0

这就是我最终做的事情:

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;
        }
    }
}

网络配置:

<system.web>
    ...
    <httpRuntime maxRequestLength="51200" />
    ...
</system.web>
<system.serviceModel>
    ...
    <bindings configSource="Config\Wcf\bindings.config" />
    ...
</system.serviceModel>

绑定.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>
于 2013-08-27T14:09:19.703 回答