【问题标题】:Web Request/Upload Failing at Very EndWeb 请求/上传在最后失败
【发布时间】:2023-03-29 21:58:01
【问题描述】:

我发现我的 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: 

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

【问题讨论】:

  • @Darin Dimitrov,我不擅长解释事情,所以我认为一个视频值 2k 字......没有人会费心阅读......哈哈

标签: c# file-upload httpwebrequest


【解决方案1】:

好吧,您通过将其放入 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 抛出异常不是一个好主意...但假设我是对的,它确实会产生一个有趣的问题,即您同时尝试写太多 和数据太少:)

【讨论】:

  • 你做对了reqWriter.Write(buffer, 0, read) 解决了这个问题。就像你说的,在最后一个 pass 小于 25600bytes 时,它试图写入 25600 bytes + 设置的内容长度,所以发生了异常。我也想跟踪进度,memStream.WriteTo(reqStream) 会让我无法跟踪进度吗?
  • @jiewmeng:嗯,这部分取决于请求流是否被缓冲。如果是这样,那么无论如何您都不会真正跟踪进度。否则,您可以保留现有代码但不使用 reqWriter - 只需直接写入流即可。
【解决方案2】:

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

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

reqWriter.Write(buffer, 0, read);

【讨论】:

  • 嗯,buffer总是包含 25600 字节的数据。这不像数组本身会增长和缩小。它们可能只是不是非常有用字节。
  • 正确,但是缓冲区的一部分是他需要写入的,多少取决于读取了多少字节。
  • @Shiv:当然——这只是“不包含 20k 数据”和“不包含 应该写入的 20k 数据”之间的挑剔。
  • @Jon 的“数据”就是我的意思,“数据”不是字节。我看到你已经编辑了你的答案以包含我所说的内容并且也得到了积分);
  • @Shiv:我的回答在你的回答发布之前已经包含了基本点——但我已经更明确了。我希望你承认我的回答比你的回答包含更多的信息——包括为什么它实际上失败了。
猜你喜欢
  • 2020-01-13
  • 2016-09-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-10
  • 2012-03-07
相关资源
最近更新 更多