C#HttpWebRequest的表单提交与进度跟踪(上传可能很大的文件)表单、进度、很大、上传

2023-09-03 02:52:57 作者:毛爷爷脸红的时候最可爱

我有一个WinForms应用程序我正在写的帖子文件添加到Web应用程序(不是我的)。我有东西工作得很好,只要发布的文件本身去的,我的问题是,我想提供一些指示,我与发送的请求走多远。

在code以下是我尝试使用BeginGetResponse为此 - 这是我发现的请求还是块

在哪里我可以开始看有什么建议?

 公共无效虚拟()
    {
        字典<字符串,字符串>田=新字典<字符串,字符串>();
        fields.Add(钥匙,东西);

        HttpWebRequest的HR = WebRequest.Create(http://somesite.com/api/something.xml)作为HttpWebRequest的;
        串绑定=----------------------------+ DateTime.Now.Ticks.ToString(×);
        hr.ContentType =的multipart / form-data的;边界=+绑定;
        hr.Method =POST;
        hr.KeepAlive = TRUE;
        hr.Credentials = CredentialCache.DefaultCredentials;

        byte []的boundBytes = Encoding.ASCII.GetBytes(\ r \ N--+束缚+\ r \ N);
        字符串formDataTemplate =\ r \ N--+束缚+\ r \ nContent处置:表格数据;名称= \{0} \; \ r \ñ\ r \ N {1};

        流s = hr.GetRequestStream();

        的foreach(在fields.Keys字符串键)
        {
            byte []的formItemBytes = Encoding.UTF8.GetBytes(
                的String.Format(formDataTemplate,重点,领域[关键]));
            s.Write(formItemBytes,0,formItemBytes.Length);
        }

        s.Write(boundBytes,0,boundBytes.Length);

        串HeaderTemplate中=
            内容处置:表格数据;名称= \{0} \文件名= \{1} \\ r \ N含量类型:应用程序/八位字节流\ r \ñ\ r \ N ;

        名单<字符串>文件=新的名单,其中,串> {使用Server.Mappath(/图片/ Phillip.jpg)};

        的foreach(在文件中的字符串F)
        {
            byte []的headerBytes = Encoding.UTF8.GetBytes(
                的String.Format(HeaderTemplate中,图像,F));

            s.Write(headerBytes,0,headerBytes.Length);
            的FileStream FS =新的FileStream(F,FileMode.Open,FileAccess.Read);
            INT读取动作= 0;
            byte []的缓冲区=新的字节[1024];
            而((读取动作= fs.Read(缓冲液,0,buffer.Length))!= 0)
            {
                s.Write(缓冲液,0,buffer.Length);
            }

            s.Write(boundBytes,0,boundBytes.Length);
            fs.Close();
        }

        S.CLOSE();

        字符串respString =;
        hr.BeginGetResponse((IAsyncResult的RES)=>
            {
                WebResponse类RESP =((HttpWebRequest的)res.AsyncState).EndGetResponse(RES);

                StreamReader的水库$ P $帕德尔=新的StreamReader(resp.GetResponseStream());
                respString =水库preader.ReadToEnd();
                resp.Close();
                RESP = NULL;
            },HR);

        而(!hr.HaveResponse)
        {
            Debug.Write(你好鲍勃!);
            Thread.sleep代码(150);
        }

        Debug.Write(respString);
        HR = NULL;
    }
 

解决方案

好了,理解了它。该HttpWebRequest对象,如果设置了CONTENTLENGTH属性,将其直接连接的ResponseStream到网络插座,当你调用GetRequestStream()。这就可以让你直接写入此流来跟踪你的进步。

伪code:

 请求R = CreateWebRequest(URL)
r.ContentLength = CalculateRequestLength(字段,文件)
流requestStream = r.GetRequestStream()
而(MOREDATA)
{
  requestStream.write(someData);
  的UpdateProgress();
}
r.GetResponse();
 

工作code:

 公共无效虚拟()
    {
        字典<字符串,字符串>田=新字典<字符串,字符串>();
        fields.Add(钥匙,东西);

        HttpWebRequest的HR = WebRequest.Create(http://imgur.com/api/upload.xml)作为HttpWebRequest的;
        串绑定=----------------------------+ DateTime.Now.Ticks.ToString(×);
        hr.ContentType =的multipart / form-data的;边界=+绑定;
        hr.Method =POST;
        hr.KeepAlive = TRUE;
        hr.Credentials = CredentialCache.DefaultCredentials;

        byte []的boundBytes = Encoding.ASCII.GetBytes(\ r \ N--+束缚+\ r \ N);
        字符串formDataTemplate =\ r \ N--+束缚+\ r \ nContent处置:表格数据;名称= \{0} \; \ r \ñ\ r \ N {1};

        //添加字段+的边界
        MemoryStream的fieldData =新的MemoryStream();
        的foreach(在fields.Keys字符串键)
        {
            byte []的formItemBytes = Encoding.UTF8.GetBytes(
                的String.Format(formDataTemplate,重点,领域[关键]));
            fieldData.Write(formItemBytes,0,formItemBytes.Length);
        }
        fieldData.Write(boundBytes,0,boundBytes.Length);

        //计算我们寄期望于总长度
        名单<字符串>文件=新的名单,其中,串> {使用Server.Mappath(/图片/ Phillip.jpg)};
        串HeaderTemplate中=
            内容处置:表格数据;名称= \{0} \文件名= \{1} \\ r \ N含量类型:应用程序/八位字节流\ r \ñ\ r \ N ;
        长fileBytes = 0;
        的foreach(在文件中的字符串F)
        {
            byte []的headerBytes = Encoding.UTF8.GetBytes(
                的String.Format(HeaderTemplate中,图像,F));
            的FileStream FS =新的FileStream(F,FileMode.Open,FileAccess.Read);

            fileBytes + = headerBytes.Length;
            fileBytes + = fs.Length;
            fileBytes + = boundBytes.Length;
            fs.Close();
        }

        hr.ContentLength = fieldData.Length + fileBytes;

        流s = hr.GetRequestStream();
        //写字段请求流
        的Debug.WriteLine(发送现场数据);
        fieldData.WriteTo(多个);

        //将文件写入请求流
        的Debug.WriteLine(发送文件数据);
        的foreach(在文件中的字符串F)
        {
            byte []的headerBytes = Encoding.UTF8.GetBytes(
                的String.Format(HeaderTemplate中,图像,F));
            s.Write(headerBytes,0,headerBytes.Length);

            的FileStream FS =新的FileStream(F,FileMode.Open,FileAccess.Read);
            INT读取动作= 0;
            长bytesSoFar = 0;
            byte []的缓冲区=新的字节[10240]
            而((读取动作= fs.Read(缓冲液,0,buffer.Length))!= 0)
            {
                bytesSoFar + =读取动作;
                s.Write(缓冲液,0,读取动作);
                的Debug.WriteLine(的String.Format(发送文件数据{0:0.000}%,(bytesSoFar * 100.0f)/ fs.Length));
            }

            s.Write(boundBytes,0,boundBytes.Length);
            fs.Close();
        }

        S.CLOSE();

        GetResponseDel D =新GetResponseDel(GetResponse的);
        ResponseData数据=新ResponseData {德尔= D};
        d.BeginInvoke(小时,EndGetResponse,数据);

        而(!hr.HaveResponse)
        {
            Debug.Write(等待回应+\ N);
            Thread.sleep代码(150);
        }

        Debug.Write(data.responseString);
        HR = NULL;
    }

    委托WebResponse类GetResponseDel(HttpWebRequest的小时);
    私人WebResponse类的GetResponse(HttpWebRequest的HR)
    {
        返回hr.GetResponse();
    }

    类ResponseData
    {
        公共GetResponseDel德尔{获得;组; }
        公共字符串responseString {获得;组; }
    }

    私人无效EndGetResponse(IAsyncResult的RES)
    {
        ResponseData数据=(ResponseData)res.AsyncState;
        GetResponseDel D = data.del;

        WebResponse类R = d.EndInvoke(RES);
        data.responseString =新的StreamReader(r.GetResponseStream())ReadToEnd()。
    }
 
表格爆改大师的福音 谷歌发布新效率工具 Tables

I've got a winforms application I'm writing that posts files to a web application (not mine). I've got things working just fine as far as posting the files themselves go, my issue is that I'd like to provide some indication of how far along I am with the sending the request.

The code below is my attempt to use BeginGetResponse to that end - and this is where I discovered that the Request still blocks.

Any suggestions on where I can begin to look?

    public void Dummy()
    {
        Dictionary<string, string> fields = new Dictionary<string, string>();
        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<string> files = new List<string> { 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;
    }

解决方案

Ok, figured it out. The HttpWebRequest object, if you set the ContentLength property, will directly connect it's ResponseStream to the network socket when you call GetRequestStream(). This then allows you to track your progress by writing directly to this stream.

Pseudo Code:

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

Working Code:

   public void Dummy()
    {
        Dictionary<string, string> fields = new Dictionary<string, string>();
        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<string> files = new List<string> { 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();
    }