Web请求/上传在最后失败

Jie*_*eng 9 c# file-upload httpwebrequest

我发现我的HTTPWebRequest上传在上传结束时失败了......如本视频@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);
    }
Run Code Online (Sandbox Code Playgroud)

我不知道你是否需要更多的代码,我只是不想在这里垃圾邮件代码.以下例外

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: 
Run Code Online (Sandbox Code Playgroud)

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

Jon*_*eet 15

好吧,你是通过把它放在一个using声明中来关闭流- 但你应该关闭它,所以这不太可能成为问题.

有几点要点:

  • 我不会在BinaryWriter这里使用.它不会给你买任何东西.直接写入流.
  • 如果memStreamMemoryStream,您可以使用WriteTo:

    using (var reqStream = req.GetRequestStream())
    {
        memStream.WriteTo(reqStream);
    }
    
    Run Code Online (Sandbox Code Playgroud)

    这意味着你不会得到你的诊断,但它确实使代码更简单:)

现在,至于发生了什么...我的猜测是你在调用中得到了一个异常Write,但是异常被有效的替换为关闭流引发的异常.

我知道为什么会抛出异常......

你在任何地方设置内容长度?因为你可能会重复它.看看这一行:

reqWriter.Write(buffer);
Run Code Online (Sandbox Code Playgroud)

这是在循环的每次迭代中写出整个缓冲区,而忽略了您刚读取的数据量.您已经分配了读入变量的字节数read,但之后您永远不会使用该值.您可以通过将其更改为来解决此问题

reqWriter.Write(buffer, 0, read);
Run Code Online (Sandbox Code Playgroud)

......但我个人不会.我要么直接使用MemoryStream.WriteTo 直接写入请求流......正如我之前所说,BinaryWriter实际上并没有给你买任何东西.

无论如何,在每个请求的当前代码中,无论内容长度如何,都要尝试写入25600字节的倍数.如果请求流注意到并抛出异常,我不会感到惊讶.让我们假装我们有30000字节的数据.我怀疑序列是这样的:

  • 内容长度设置为30000
  • 获取流并输入using语句
  • 从内存流中读取25600个字节
  • 写出25600字节:流验证这是正确的
  • 从内存流中读取4400个字节(即所有剩余数据)
  • 尝试写入25600个字节:stream 立即确定它是无效的,然后抛出一个IOException
  • 然后语句的隐式finallyusing处理流,关闭它
  • 流注意到只有25600个字节已成功写入,这是不够的,因此抛出异常

这种事情使得库从库中抛出异常是一个坏主意Dispose...但是假设我是对的,它确实给出了一个有趣的问题,你曾经同时试图写太多而且数据太少:)