带有进度跟踪的C#HttpWebRequest表单post(用于上传可能存在的大文件)

我有一个winforms应用程序,我写的是将文件发布到Web应用程序(不是我的)。 就发布文件本身来说,我的工作做得很好,我的问题是我想提供一些指示,告诉我发送请求的程度

下面的代码是我尝试使用BeginGetResponse到这一步 – 这是我发现请求仍然阻止的地方。

关于我可以从哪里开始看的任何建议?

public void Dummy() { Dictionary fields = new Dictionary(); fields.Add("key", "something"); HttpWebRequest hr = WebRequest.Create("http://somesite.com/api/something.xml") as HttpWebRequest; string bound = "----------------------------" + DateTime.Now.Ticks.ToString("x"); hr.ContentType = "multipart/form-data; boundary=" + bound; hr.Method = "POST"; hr.KeepAlive = true; hr.Credentials = CredentialCache.DefaultCredentials; byte[] boundBytes = Encoding.ASCII.GetBytes("\r\n--" + bound + "\r\n"); string formDataTemplate = "\r\n--" + bound + "\r\nContent-Disposition: form-data; name=\"{0}\";\r\n\r\n{1}"; Stream s = hr.GetRequestStream(); foreach (string key in fields.Keys) { byte[] formItemBytes = Encoding.UTF8.GetBytes( string.Format(formDataTemplate, key, fields[key])); s.Write(formItemBytes, 0, formItemBytes.Length); } s.Write(boundBytes, 0, boundBytes.Length); string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\n Content-Type: application/octet-stream\r\n\r\n"; List files = new List { Server.MapPath("/Images/Phillip.jpg") }; foreach (string f in files) { byte[] headerBytes = Encoding.UTF8.GetBytes( String.Format(headerTemplate, "image", f)); s.Write(headerBytes, 0, headerBytes.Length); FileStream fs = new FileStream(f, FileMode.Open, FileAccess.Read); int bytesRead = 0; byte[] buffer = new byte[1024]; while ((bytesRead = fs.Read(buffer, 0, buffer.Length)) != 0) { s.Write(buffer, 0, buffer.Length); } s.Write(boundBytes, 0, boundBytes.Length); fs.Close(); } s.Close(); string respString =""; hr.BeginGetResponse((IAsyncResult res) => { WebResponse resp = ((HttpWebRequest)res.AsyncState).EndGetResponse(res); StreamReader respReader = new StreamReader(resp.GetResponseStream()); respString = respReader.ReadToEnd(); resp.Close(); resp = null; }, hr); while (!hr.HaveResponse) { Debug.Write("hiya bob!"); Thread.Sleep(150); } Debug.Write(respString); hr = null; } 

好吧,想通了。 如果设置ContentLength属性,HttpWebRequest对象将在调用GetRequestStream()时将其ResponseStream直接连接到网络套接字。 然后,您可以直接写入此流来跟踪进度。

伪代码:

 Request r = CreateWebRequest(Url) r.ContentLength = CalculateRequestLength(fields, files) Stream requestStream = r.GetRequestStream() while(moreData) { requestStream.write(someData); UpdateProgress(); } r.GetResponse(); 

工作守则:

  public void Dummy() { Dictionary fields = new Dictionary(); fields.Add("key", "something"); HttpWebRequest hr = WebRequest.Create("http://imgur.com/api/upload.xml") as HttpWebRequest; string bound = "----------------------------" + DateTime.Now.Ticks.ToString("x"); hr.ContentType = "multipart/form-data; boundary=" + bound; hr.Method = "POST"; hr.KeepAlive = true; hr.Credentials = CredentialCache.DefaultCredentials; byte[] boundBytes = Encoding.ASCII.GetBytes("\r\n--" + bound + "\r\n"); string formDataTemplate = "\r\n--" + bound + "\r\nContent-Disposition: form-data; name=\"{0}\";\r\n\r\n{1}"; //add fields + a boundary MemoryStream fieldData = new MemoryStream(); foreach (string key in fields.Keys) { byte[] formItemBytes = Encoding.UTF8.GetBytes( string.Format(formDataTemplate, key, fields[key])); fieldData.Write(formItemBytes, 0, formItemBytes.Length); } fieldData.Write(boundBytes, 0, boundBytes.Length); //calculate the total length we expect to send List files = new List { Server.MapPath("/Images/Phillip.jpg") }; string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\n Content-Type: application/octet-stream\r\n\r\n"; long fileBytes = 0; foreach (string f in files) { byte[] headerBytes = Encoding.UTF8.GetBytes( String.Format(headerTemplate, "image", f)); FileStream fs = new FileStream(f, FileMode.Open, FileAccess.Read); fileBytes += headerBytes.Length; fileBytes += fs.Length; fileBytes += boundBytes.Length; fs.Close(); } hr.ContentLength = fieldData.Length + fileBytes; Stream s = hr.GetRequestStream(); //write the fields to the request stream Debug.WriteLine("sending field data"); fieldData.WriteTo(s); //write the files to the request stream Debug.WriteLine("sending file data"); foreach (string f in files) { byte[] headerBytes = Encoding.UTF8.GetBytes( String.Format(headerTemplate, "image", f)); s.Write(headerBytes, 0, headerBytes.Length); FileStream fs = new FileStream(f, FileMode.Open, FileAccess.Read); int bytesRead = 0; long bytesSoFar = 0; byte[] buffer = new byte[10240]; while ((bytesRead = fs.Read(buffer, 0, buffer.Length)) != 0) { bytesSoFar += bytesRead; s.Write(buffer, 0, bytesRead); Debug.WriteLine(String.Format("sending file data {0:0.000}%", (bytesSoFar * 100.0f) / fs.Length)); } s.Write(boundBytes, 0, boundBytes.Length); fs.Close(); } s.Close(); GetResponseDel d = new GetResponseDel(GetResponse); ResponseData data = new ResponseData { del = d }; d.BeginInvoke(hr, EndGetResponse, data); while (!hr.HaveResponse) { Debug.Write("waiting for response" + "\n"); Thread.Sleep(150); } Debug.Write(data.responseString); hr = null; } delegate WebResponse GetResponseDel(HttpWebRequest hr); private WebResponse GetResponse(HttpWebRequest hr) { return hr.GetResponse(); } class ResponseData { public GetResponseDel del { get; set; } public string responseString { get; set; } } private void EndGetResponse(IAsyncResult res) { ResponseData data = (ResponseData)res.AsyncState; GetResponseDel d = data.del; WebResponse r = d.EndInvoke(res); data.responseString = new StreamReader(r.GetResponseStream()).ReadToEnd(); }