Publication de formulaire C # HttpWebRequest avec suivi de la progression (pour le téléchargement de fichiers potentiellement volumineux)

J’ai une application winforms que j’écris et qui poste des fichiers sur une application Web (pas la mienne). Les choses marchent bien pour ce qui est de l’affichage des fichiers eux-mêmes. Mon problème est que j’aimerais donner une indication de l’état d’avancement de l’envoi de la demande .

Le code ci-dessous est ma tentative d’utiliser BeginGetResponse à cette fin – et c’est là que j’ai découvert que la demande bloquait toujours.

Des suggestions sur où je peux commencer à regarder?

public void Dummy() { Dictionary fields = new Dictionary(); fields.Add("key", "something"); HttpWebRequest hr = WebRequest.Create("http://somesite.com/api/something.xml") as HttpWebRequest; ssortingng bound = "----------------------------" + DateTime.Now.Ticks.ToSsortingng("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"); ssortingng formDataTemplate = "\r\n--" + bound + "\r\nContent-Disposition: form-data; name=\"{0}\";\r\n\r\n{1}"; Stream s = hr.GetRequestStream(); foreach (ssortingng key in fields.Keys) { byte[] formItemBytes = Encoding.UTF8.GetBytes( ssortingng.Format(formDataTemplate, key, fields[key])); s.Write(formItemBytes, 0, formItemBytes.Length); } s.Write(boundBytes, 0, boundBytes.Length); ssortingng 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 (ssortingng f in files) { byte[] headerBytes = Encoding.UTF8.GetBytes( Ssortingng.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(); ssortingng respSsortingng =""; hr.BeginGetResponse((IAsyncResult res) => { WebResponse resp = ((HttpWebRequest)res.AsyncState).EndGetResponse(res); StreamReader respReader = new StreamReader(resp.GetResponseStream()); respSsortingng = respReader.ReadToEnd(); resp.Close(); resp = null; }, hr); while (!hr.HaveResponse) { Debug.Write("hiya bob!"); Thread.Sleep(150); } Debug.Write(respSsortingng); hr = null; } 

Ok, compris. L’object HttpWebRequest, si vous définissez la propriété ContentLength, connectera directement son ResponseStream au socket réseau lorsque vous appelez GetRequestStream (). Cela vous permet ensuite de suivre vos progrès en écrivant directement dans ce stream.

Pseudo Code:

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

Code de travail:

  public void Dummy() { Dictionary fields = new Dictionary(); fields.Add("key", "something"); HttpWebRequest hr = WebRequest.Create("http://imgur.com/api/upload.xml") as HttpWebRequest; ssortingng bound = "----------------------------" + DateTime.Now.Ticks.ToSsortingng("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"); ssortingng 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 (ssortingng key in fields.Keys) { byte[] formItemBytes = Encoding.UTF8.GetBytes( ssortingng.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") }; ssortingng headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\n Content-Type: application/octet-stream\r\n\r\n"; long fileBytes = 0; foreach (ssortingng f in files) { byte[] headerBytes = Encoding.UTF8.GetBytes( Ssortingng.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 (ssortingng f in files) { byte[] headerBytes = Encoding.UTF8.GetBytes( Ssortingng.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(Ssortingng.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.responseSsortingng); hr = null; } delegate WebResponse GetResponseDel(HttpWebRequest hr); private WebResponse GetResponse(HttpWebRequest hr) { return hr.GetResponse(); } class ResponseData { public GetResponseDel del { get; set; } public ssortingng responseSsortingng { get; set; } } private void EndGetResponse(IAsyncResult res) { ResponseData data = (ResponseData)res.AsyncState; GetResponseDel d = data.del; WebResponse r = d.EndInvoke(res); data.responseSsortingng = new StreamReader(r.GetResponseStream()).ReadToEnd(); }