2010-11-21 42 views
9

我發現我的HttpWebRequest的上傳是在上傳的最後失敗...如圖this video @Screenr的Web請求/上傳失敗,在最後一刻

我的代碼是像下面

using (var reqStream = req.GetRequestStream()) 
{ 
    BinaryWriter reqWriter = new BinaryWriter(reqStream); 
    byte[] buffer = new byte[25600]; // 20KB Buffer 
    int read = 0, bytesRead = 0; 
    while ((read = memStream.Read(buffer, 0, buffer.Length)) > 0) { 
     reqWriter.Write(buffer); // at the very last loop, this line causes the error 
     bytesRead += read; 
     Debug.WriteLine("Percent Done: " + ((double)bytesRead/memStream.Length * 100) + "% " + DateTime.Now); 
    } 

我不知道你是否需要更多的代碼,我只是不想在這裏垃圾郵件代碼。下面的例外

System.Net.WebException was caught 
    Message=The request was aborted: The request was canceled. 
    Source=System 
    StackTrace: 
     at System.Net.ConnectStream.CloseInternal(Boolean internalCall, Boolean aborting) 
     at System.Net.ConnectStream.System.Net.ICloseEx.CloseEx(CloseExState closeState) 
     at System.Net.ConnectStream.Dispose(Boolean disposing) 
     at System.IO.Stream.Close() 
     at System.IO.Stream.Dispose() 
     at QuickImageUpload.ViewModels.ShellViewModel.UploadImage(String filename, String contentType, Byte[] image) in D:\Projects\QuickImageUpload\QuickImageUpload\ViewModels\ShellViewModel.cs:line 190 
    InnerException: System.IO.IOException 
     Message=Cannot close stream until all bytes are written. 
     Source=System 
     StackTrace: 
      at System.Net.ConnectStream.CloseInternal(Boolean internalCall, Boolean aborting) 
     InnerException: 

注意內部異常「直到寫入所有字節才能關閉流」。但是我沒有關閉這個循環中的任何流嗎?

+0

+1視頻內容:-) – 2010-11-21 09:18:17

+0

@Darin季米特洛夫,我不擅長解釋的事情,所以我想視頻將是值得2K字......東西沒有人會打擾閱讀...哈哈 – 2010-11-21 10:51:05

回答

15

那麼,你通過將它放在using聲明中來關閉流 - 但你應該正在關閉它,所以這不太可能是問題。

幾個百分點入手:

  • 我不會用一個BinaryWriter這裏。它不會爲你買東西。直接寫入流。
  • 如果memStreamMemoryStream,你可以使用WriteTo

    using (var reqStream = req.GetRequestStream()) 
    { 
        memStream.WriteTo(reqStream); 
    } 
    

    這意味着你不會得到你的診斷,但它確實使代碼更簡單:)

現在,至於發生了什麼...我的猜測是你在Write的調用中得到一個異常,但是這個異常正在被關閉流的異常所取代。

我有一個想法,爲什麼一個可能拋出異常,太...

你設置的內容長度的任何地方?因爲你可能會過去。看這句話:

reqWriter.Write(buffer); 

這是出於寫入整個緩衝區上迭代循環的,不理你了多少流量剛纔讀。您已將讀取的字節數分配到變量read中,但您從未使用該值。你可以通過改變它來解決這個問題

reqWriter.Write(buffer, 0, read); 

......但我個人不會。我會要麼只是使用MemoryStream.WriteTo直接寫入請求流......正如我之前所說,BinaryWriter實際上並沒有購買任何東西。

無論如何,在您當前的每個請求的代碼中,無論您的內容長度如何,您都會嘗試寫入25600字節的倍數。如果請求流發現並拋出異常,我不會感到驚訝。假設我們有30000字節的數據。我懷疑的順序是這樣的:

  • 內容長度設置爲30000
  • 獲取流和using語句
  • 從內存中讀取數據流25600個字節
  • 寫入25600字節進行輸入:流驗證了這是正確的
  • 從內存中讀取數據流4400個字節(即所有剩餘的數據)
  • 嘗試寫25600個字節:流立即決定這是無效的,並拋出一個IOException
  • using聲明的隱含finally塊,然後部署流,其封閉,只有25600個字節已經成功地寫它
  • 流通知,這是不夠的,所以拋出例外

這是這樣的事情,它使一個壞主意,讓圖書館從Dispose拋出異常......但假設我是正確的,它確實給你已經同時嘗試寫得太好玩的問題太多太少的數據:)

+0

你說得對嗎'reqWriter.Write(buffer,0,read)'解決了這個問題。就像你說的,在最後一次傳輸時,如果少於25600字節,它會嘗試寫入25600字節+內容長度已設置,因此發生異常。我也想追蹤進度,'memStream.WriteTo(reqStream)'會讓我無法跟蹤進度嗎? – 2010-11-21 11:27:45

+0

@jiewmeng:嗯,部分取決於請求流是否被緩衝。如果是這樣,那麼你無論如何也不會真正跟蹤進度。否則,您可以保留現有的代碼,但不使用'reqWriter' - 只需直接寫入流。 – 2010-11-21 11:43:59

4

您不能寫「緩衝區」,因爲到最後「緩衝區」不包含20k的數據。

因此,當你做一個memStream.Read時,它會返回實際讀取的字節數。你在寫作時需要使用這些知識/信息。

reqWriter.Write(buffer, 0, read); 
+1

好吧,'buffer'將總是*包含25600字節的數據。這不像數組本身的增長和縮小。它們可能不是非常有用的*字節。 – 2010-11-21 08:55:44

+0

是正確的,但是緩衝區的一部分是他需要寫入的內容,多少是由讀取多少字節決定的。 – 2010-11-21 09:21:08

+0

@Shiv:當然 - 這只是「不包含20k數據」和「不包含20k應該寫入的數據*」之間的挑逗。 – 2010-11-21 11:44:36