ASP.NET不一致的PDF文件下载结果

时间:2012-10-01 01:35:30

标签: asp.net pdf browser download

我正在开发一个包含树视图的ASP.NET(3.5)网站;节点的值设置为PDF文件的文件路径(在服务器上)。当用户单击treenode时,服务器端代码获取节点值(文件路径),创建FileInfo对象,并(在正确设置所有标头Content-type,Cache-Control等之后)调用Response.TransmitFile( xxxxpath)发送到用户的浏览器。

这适用于各大浏览器,主要设备(PC,Mac,iOS设备)。文件正确下载并在用户的计算机上打开。但在某些设备和某些浏览器上,PDF文件无法打开。在Android设备上,似乎Firefox正确下载并打开PDF,但是Android浏览器没有。在Kindle Fire上,Silk浏览器似乎成功下载了该文件,但在尝试打开它时,我看到一个错误:“找不到PDF预告片”....或者它说PDF受DRM保护(它是不)。我没有在Fire上尝试过另一个浏览器(如果有的话)。

我已尝试在静态HTML标记中使用锚链接,并且问题浏览器似乎在以这种方式访问​​时正确下载和显示PDF。似乎存在一个问题(不一致?)与ASP.NET在通过代码完成时将响应发送到浏览器的方式。我已经使用了Response.Flush,Response.WriteFile,Response.BinaryWrite,Response.Close,Response.End等,它们都产生了相同的结果:MOST浏览器处理文件,但是SOME无法处理PDF。

那么,ASP.NET构建Response对象的方式是否存在一些问题(特别是在发回PDF时)某些浏览器不喜欢? TIA。

1 个答案:

答案 0 :(得分:1)

很简单,你问题的答案是“不”。如果您对是否正确执行此操作有疑问,可能需要发布代码;否则:'不'。 :)

我认为你提到的浏览器比写入Response流更简单,更可靠。

这里提供的参考是一种尝试和使用iHttpHandler的方法:

    public void ProcessRequest(System.Web.HttpContext context)
    {
        string sFilePath = context.Server.MapPath(String.Concat("~/App_LocalResources", context.Request.QueryString["path"]));
        try
        {
            context.Response.Clear();
            context.Response.ContentType = "application/octet-stream";

            int iReadLength = 16384;
            int iLastReadLength = iReadLength;
            byte[] buffer = new byte[iReadLength];
            if (System.IO.File.Exists(sFilePath))
            {
                System.IO.FileInfo fInfo = new System.IO.FileInfo(sFilePath);
                context.Response.AddHeader("Content-Length", fInfo.Length.ToString());
                context.Response.AddHeader("Content-Disposition", String.Format("attachment; filename=\"{0}\"", fInfo.Name));
                using (System.IO.FileStream input = new System.IO.FileStream(sFilePath, System.IO.FileMode.Open, System.IO.FileAccess.Read))
                {
                    try
                    {
                        while (iLastReadLength > 0 && context.Response.IsClientConnected)
                        {
                            iLastReadLength = input.Read(buffer, 0, iLastReadLength);

                            if (iLastReadLength > 0)
                            {
                                context.Response.OutputStream.Write(buffer, 0, iLastReadLength);
                                context.Response.OutputStream.Flush();
                            }
                        }
                        context.Response.Flush();
                    }
                    catch
                    {
                    }
                    finally
                    {
                        input.Close();
                    }
                }
            }
        }
        catch
        {
        }
        finally
        {
        }
    }

由于您已经表明要从其他位置提取文件,因此以下是将其写入内存流的方法。只需从远程服务器(或文件流,Sql二进制阅读器,实际上)中取出您的Response Stream,然后重置您的MemoryStream位置,然后使用上述功能写入您的客户端的Response流。

int iReadLength = 16384;
long lLastReadLength = iReadLength;
long lDataIndex = 0;
byte[] buffer = new byte[iReadLength];
using (System.IO.MemoryStream msTemp = new System.IO.MemoryStream())
{
    while (lLastReadLength > 0)
    {
        lLastReadLength = reader.GetBytes(0, lDataIndex, buffer, 0, iReadLength);
        lDataIndex += lLastReadLength;

        if (lLastReadLength > 0)
        {
            msTemp.Write(buffer, 0, Convert.ToInt32(lLastReadLength));
            msTemp.Flush();
        }
    }

    // Reset Memory Position
    msTemp.Position = 0;

    // Now write to the Response Stream here
}