我正在开发一个包含树视图的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。
答案 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
}