title: Uploading HTTP progress tracking
body: <p>I've got WPF application I'm writing that posts files to one of social networks.
  Upload itself working just fine, but I'd like to provide some indication of how far along I am with the uploading.</p>
  
  <p>I tried a bunch of ways to do this:</p>
  
  <p>1) HttpWebRequest.GetStream method:</p>
  
  <pre><code>using (
   var FS = File.Open(
    localFilePath, FileMode.Open, FileAccess.Read, FileShare.Read))
  {
      long len = FS.Length;
      HttpWebRequest request = (HttpWebRequest) WebRequest.Create(url);
      request.Method = "POST";
      request.ProtocolVersion = HttpVersion.Version11;
      request.ContentType = "multipart/form-data; boundary=--AaB03x";
      //predata and postdata is two byte[] arrays, that contains
      //strings for MIME file upload (defined above and is not important)
      request.ContentLength = predata.Length + FS.Length + postdata.Length;
      request.AllowWriteStreamBuffering = false;
      using (var reqStream = request.GetRequestStream())
      {
          reqStream.Write(predata, 0, predata.Length);
          int bytesRead = 0;
          int totalRead = 0;
          do
          {
              bytesRead = FS.Read(fileData, 0, MaxContentSize);
              totalRead += bytesRead;
              reqStream.Write(fileData, 0, bytesRead);
              reqStream.Flush(); //trying with and without this
              //this part will show progress in percents
              sop.prct = (int) ((100*totalRead)/len);
          } while (bytesRead &gt; 0);
          reqStream.Write(postdata, 0, postdata.Length);
      }
      HttpWebResponse responce = (HttpWebResponse) request.GetResponse();
      using (var respStream = responce.GetResponseStream())
      {
          //do things
      }
  }
  </code></pre>
  
  <p>2) WebClient way (much shorter):</p>
  
  <pre><code>void UploadFile (url, localFilePath)
  {
      ...
      WebClient client = new WebClient();
      client.UploadProgressChanged += new UploadProgressChangedEventHandler(UploadPartDone);
      client.UploadFileCompleted += new UploadFileCompletedEventHandler(UploadComplete);
      client.UploadFileAsync(new Uri(url), localFilePath);
      done.WaitOne();
  
      //do things with responce, received from UploadComplete
      JavaScriptSerializer jssSer = new JavaScriptSerializer();
      return jssSer.Deserialize&lt;UniversalJSONAnswer&gt;(utf8.GetString(UploadFileResponce));
      //so on...
      ...
  }
  
  void UploadComplete(object sender, UploadFileCompletedEventArgs e)
  {
      UploadFileResponce=e.Result;
      done.Set();
  }
  
  void UploadPartDone(object sender, UploadProgressChangedEventArgs e)
  {
      //this part expected to show progress
      sop.prct=(int)(100*e.BytesSent/e.TotalBytesToSend);
  }
  </code></pre>
  
  <p>3) Even TcpClient way:</p>
  
  <pre><code>using (
   var FS = File.Open(
    localFilePath, FileMode.Open, FileAccess.Read, FileShare.Read))
  {
      long len = FS.Length;
      long totalRead = 0;
      using (var client = new TcpClient(urli.Host, urli.Port))
      {
          using (var clearstream = client.GetStream())
          {
              using (var writer = new StreamWriter(clearstream))
              using (var reader = new StreamReader(clearstream))
              {
                  //set progress to 0
                  sop.prct = 0;
                  // Send request headers
                  writer.WriteLine("POST " + urli.AbsoluteUri + " HTTP/1.1");
                  writer.WriteLine("Content-Type: multipart/form-data; boundary=--AaB03x");
                  writer.WriteLine("Host: " + urli.Host);
                  writer.WriteLine("Content-Length: " + (predata.Length + len + postdata.Length).ToString());
                  writer.WriteLine();
                  //some data for MIME
                  writer.Write(utf8.GetString(predata));
                  writer.Flush();
                  int bytesRead;
                  do
                  {
                      bytesRead = FS.Read(fileData, 0, MaxContentSize);
                      totalRead += bytesRead;
                      writer.BaseStream.Write(fileData, 0, bytesRead);
                      writer.BaseStream.Flush();
                      sop.prct = (int) ((100*totalRead)/len);
                  } while (bytesRead &gt; 0)
                  writer.Write(utf8.GetString(postdata));
                  writer.Flush();
                  //read line of response and do other thigs...
                  respStr = reader.ReadLine();
                  ...
              }
          }
      }
  }
  </code></pre>
  
  <p>In all cases the file was successfully sent to the server.
  But always progress looks like this: for a few seconds it runs from 0 to 100 and then waits until file actually uploading (about 5 minutes - file is 400MB).</p>
  
  <p>So I think the data from a file is buffered somewhere and I'm tracking not uploading, but buffering data. And then must wait until it's uploaded.</p>
  
  <p>My questions are:</p>
  
  <p>1) Is there any way to track <em>actual</em> uploading data? That the method Stream.Write() or Flush() (which as I read somewhere, does not work for NetworkStream) did not return until it receives confirmation from the server that the TCP packets received.</p>
  
  <p>2) Or can I deny buffering (AllowWriteStreamBUffering for HttpWebRequest doesn't work)?</p>
  
  <p>3) And does it make sense to go further "down" and try with Sockets?</p>
  
  <p><strong>updated:</strong></p>
  
  <p>To avoid any doubts in the way of progress displaying on UI, I rewrote the code to log a file.
  so, here is code:</p>
  
  <pre><code>using (var LogStream=File.Open("C:\\123.txt",FileMode.Create,FileAccess.Write,FileShare.Read))
  using (var LogWriter=new StreamWriter(LogStream))
  using (var FS = File.Open(localFilePath, FileMode.Open, FileAccess.Read, FileShare.Read))
  {
      long len = FS.Length;
      HttpWebRequest request = (HttpWebRequest) WebRequest.Create(url);
      request.Timeout = 7200000; //2 hour timeout
      request.Method = "POST";
      request.ProtocolVersion = HttpVersion.Version11;
      request.ContentType = "multipart/form-data; boundary=--AaB03x";
      //predata and postdata is two byte[] arrays, that contains
      //strings for MIME file upload (defined above and is not important)
      request.ContentLength = predata.Length + FS.Length + postdata.Length;
      request.AllowWriteStreamBuffering = false;
      LogWriter.WriteLine(DateTime.Now.ToString("o") + " Start write into request stream. ");
      using (var reqStream = request.GetRequestStream())
      {
          reqStream.Write(predata, 0, predata.Length);
          int bytesRead = 0;
          int totalRead = 0;
          do
          {
              bytesRead = FS.Read(fileData, 0, MaxContentSize);
              totalRead += bytesRead;
              reqStream.Write(fileData, 0, bytesRead);
              reqStream.Flush(); //trying with and without this
              //sop.prct = (int) ((100*totalRead)/len); //this part will show progress in percents
              LogWriter.WriteLine(DateTime.Now.ToString("o") + " totalRead= " + totalRead.ToString() + " / " + len.ToString());
          } while (bytesRead &gt; 0);
          reqStream.Write(postdata, 0, postdata.Length);
      }
      LogWriter.WriteLine(DateTime.Now.ToString("o") + " All sent!!! Waiting for responce... ");
      LogWriter.Flush();
      HttpWebResponse responce = (HttpWebResponse) request.GetResponse();
      LogWriter.WriteLine(DateTime.Now.ToString("o") + " Responce received! ");
      using (var respStream = responce.GetResponseStream())
      {
          if (respStream == null) return null;
          using (var streamReader = new StreamReader(respStream))
          {
              string resp = streamReader.ReadToEnd();
              JavaScriptSerializer jssSer = new JavaScriptSerializer();
              return jssSer.Deserialize&lt;UniversalJSONAnswer&gt;(resp);
          }
      }
  }
  </code></pre>
  
  <p>and here is result (I cut the middle):</p>
  
  <pre><code>2011-11-19T22:00:54.5964408+04:00 Start write into request stream. 
  2011-11-19T22:00:54.6404433+04:00 totalRead= 1048576 / 410746880
  2011-11-19T22:00:54.6424434+04:00 totalRead= 2097152 / 410746880
  2011-11-19T22:00:54.6434435+04:00 totalRead= 3145728 / 410746880
  2011-11-19T22:00:54.6454436+04:00 totalRead= 4194304 / 410746880
  2011-11-19T22:00:54.6464437+04:00 totalRead= 5242880 / 410746880
  2011-11-19T22:00:54.6494438+04:00 totalRead= 6291456 / 410746880
  .......    
  2011-11-19T22:00:55.3434835+04:00 totalRead= 408944640 / 410746880
  2011-11-19T22:00:55.3434835+04:00 totalRead= 409993216 / 410746880
  2011-11-19T22:00:55.3464837+04:00 totalRead= 410746880 / 410746880
  2011-11-19T22:00:55.3464837+04:00 totalRead= 410746880 / 410746880
  2011-11-19T22:00:55.3464837+04:00 All sent!!! Waiting for responce... 
  2011-11-19T22:07:23.0616597+04:00 Responce received! 
  </code></pre>
  
  <p>as you can see program thinks that it uploaded ~400MB for about 2 seconds. And after 7 minutes file actually uploads and I receive responce.</p>
  
  <p><strong>updated again:</strong></p>
  
  <p>Seems to this is happening under WIndows 7 (not shure about x64 or x86).
  When I run my code uder XP everything works perfectly and progress is shown absolute correctly</p>