我有一个winforms应用程序我写的是将文件发布到Web应用程序(不是我的)。就发布文件本身来说,我的工作做得很好,我的问题是我想提供一些指示,告诉我发送请求的距离。
下面的代码是我尝试将BeginGetResponse用于此目的 - 这就是我发现请求仍然阻止的地方。
有关我可以开始查看的地方的任何建议吗?
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;
}
答案 0 :(得分:8)
好的,想通了。如果设置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<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();
}