Web请求/上传在最后失败

时间:2010-11-21 08:41:51

标签: c# file-upload httpwebrequest

我发现我的HTTPWebRequest上传在上传结束时失败了......如 this video @Screenr

所示

我的代码如下所示

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: 

注意内部异常“在写入所有字节之前无法关闭流”。但是我没有在这个循环中关闭任何流吗?

2 个答案:

答案 0 :(得分: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
  • 获取流并输入使用声明
  • 从内存流中读取25600个字节
  • 写出25600字节:stream验证这是正确的
  • 从内存流中读取4400个字节(即所有剩余数据)
  • 尝试写入25600个字节:stream 立即判断该文件无效,并抛出IOException
  • finally语句的隐式using块然后处理关闭它的流
  • 流注意到只成功写入了25600个字节,这是不够的,因此抛出异常

这种事情让图书馆从Dispose抛出异常是一个坏主意......但假设我是对的,它确实给出了你同时试图写的有趣问题很多太少的数据:)

答案 1 :(得分:4)

你不能写“缓冲区”,因为到最后“缓冲区”不包含20k的数据。

因此,当您执行memStream.Read时,它返回实际读取的字节数。你需要在写作时使用这些知识/信息。

reqWriter.Write(buffer, 0, read);