2012-10-01 23 views
1

我正在研究一個包含treeview的ASP.NET(3.5)網站;節點的值被設置爲PDF文件的文件路徑(在服務器上)。當用戶點擊treenode時,服務器端代碼獲取節點值(文件路徑),創建FileInfo對象,並且(在正確設置所有頭Content-type,Cache-Control等之後)調用Response.TransmitFile( xxxxpath)發送到用戶的瀏覽器。ASP.NET不一致的PDF文件下載結果

這適用於主要瀏覽器,主要設備(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

您是否得到了最終解決方案?幾個***所以答案***可能會給你更多的信息,如果你嘗試。 – Kiquenet

回答

1

很簡單,您的問題的答案是「否」如果您對是否正確執行操作有疑問,您可能需要發佈代碼;否則:'不'。 :)

我認爲你提到的瀏覽器比寫入響應流的簡單和建立的東西更可疑。

僅供參考這裏是一個嘗試和真正的辦法,我做到這一點使用的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二進制閱讀器,實際上就是)從您的響應流中拉出,然後重置您的MemoryStream位置,然後使用上面的功能將響應流寫入客戶端。

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 
} 
+0

我真的被卡住了。我用你的代碼(我沒有使用HttpHandler,但代碼完好無損),結果相同。我已經嘗試了十幾種不同的代碼方法,儘管它們都是通過Response將文件發送回瀏覽器的變體。如果他們最初無法下載這些文件,我已準備好投入使用,並告訴人們使用Firefox。如果我的同事不喜歡它,他們可以自己想出解決方案!感謝您的代碼和信息。 – TheDudeDude

+0

關於不使用處理程序的唯一方法是,在將所有內容寫入響應流之後(在我的示例中,在finally塊之後),您需要調用Response.End()。否則,.aspx頁面可能會向瀏覽器發送更多內容,從而可能會破壞它。並且調用Response.End永遠不會很有趣,因爲當你這樣做時,避免「線程被中止」的錯誤真的很痛苦。 –

+0

哦,我已經使用了Response.End,Response.Close和許多其他命令組合(並且只捕獲ThreadAbort異常),仍然沒有骰子。在這個網站的設置中,唯一的另一個「怪異」是鏈接到(在頁面上)的文件駐留在與web服務器不同的服務器上。在服務器端代碼中,我使用UNC名稱來檢索PDF,然後通過Response將其發回。它們不是直接鏈接(www.mysite.com/pubs/mypdf.pdf)。你認爲這可能是因爲我的文件必須由服務器檢索,服務器發送一些額外的信息與字節數組? – TheDudeDude