I am trying to make an HttpWebRequest to send data via POST to a REST web service, and then follow-up with an additional HttpWebRequest to download a response after processing.
The POST is sending binary data up to the web service, as follows:
HttpWebRequest uploadRequest = (HttpWebRequest)WebRequest.Create(baseAddress + uploadURIRequest);
uploadRequest.Timeout = Timeout.Infinite;
uploadRequest.ReadWriteTimeout = Timeout.Infinite;
uploadRequest.Method = "POST";
uploadRequest.ContentLength = fileInfo.Length;
uploadRequest.ContentType = "application/octet-stream";
using (Stream writeStream = uploadRequest.GetRequestStream())
{
using (FileStream readStream = new FileStream(fileStreamFileName, FileMode.Open, FileAccess.Read))
{
byte[] data= new byte[readStream.Length];
int bytesRead = readStream.Read(data, 0, (int)readStream.Length);
writeStream.Write(data, 0, bytesRead);
readStream.Close();
}
writeStream.Close();
}
Then the next request is made to tell the web service to process data on the server and return the status response.
HttpWebRequest processRequest = (HttpWebRequest)WebRequest.Create(baseAddress + processURIRequest);
processRequest.Timeout = 10000;
processRequest.ReadWriteTimeout = 10000;
processRequest.ContentType = "GET";
HttpWebResponse processRequestResponse = (HttpWebResponse)processRequest.GetResponse();
using (Stream processRequestResponseStream = processRequestResponse.GetResponseStream())
{
//Do stuff...
}
When I change content-type, it works for XML data. However, when I keep it as shown above with binary data, the operation always times out...even if I increase the timeout to longer than 10 seconds. The processing that it is doing should not take this long to return.
When I debug, it always hangs on the line with GetResponse:
HttpWebResponse processRequestResponse = (HttpWebResponse)processRequest.GetResponse();
Adding
HttpWebResponse uploadRequestResponse = (HttpWebResponse)uploadRequest.GetResponse();
after writing to the stream resolved this issue.
Related
i've been reading here for quite a long time, but in this case i'm not getting any further.
I'm rather new to Windows Phone development and facing the following problem.
I'm calling a webservice were I have to post a xml request message. I've got the code working in regular c# (see code below)
private static string WebRequestPostData(string url, string postData)
{
System.Net.WebRequest req = System.Net.WebRequest.Create(url);
req.ContentType = "text/xml";
req.Method = "POST";
byte[] bytes = System.Text.Encoding.ASCII.GetBytes(postData);
req.ContentLength = bytes.Length;
using (Stream os = req.GetRequestStream())
{
os.Write(bytes, 0, bytes.Length);
}
using (System.Net.WebResponse resp = req.GetResponse())
{
if (resp == null) return null;
using (System.IO.StreamReader sr = new System.IO.StreamReader(resp.GetResponseStream()))
{
return sr.ReadToEnd().Trim();
}
}
}
But for Windows Phone (8) development it needs to be async. After searching the web, and trying the various samples given here I came to the following code:
private async void DoCallWS()
{
string url = "<my_url>";
// HTTP web request
var httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
httpWebRequest.ContentType = "text/xml";
httpWebRequest.Method = "POST";
// Write the request Asynchronously
using (var stream = await Task.Factory.FromAsync<Stream>(httpWebRequest.BeginGetRequestStream,
httpWebRequest.EndGetRequestStream, null))
{
string requestXml = "<my_request_xml>";
// convert request to byte array
byte[] requestAsBytes = Encoding.UTF8.GetBytes(requestXml);
// Write the bytes to the stream
await stream.WriteAsync(requestAsBytes , 0, requestAsBytes .Length);
stream.Position = 0;
using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
{
//return reader.ReadToEnd();
string result = reader.ReadToEnd();
}
}
}
The string result has the value of my request xml message i'm trying to sent....
I'm aware that async void methodes are not preferred but i will fix that later.
I've also tried to following the solution as described by Matthias Shapiro (http://matthiasshapiro.com/2012/12/10/window-8-win-phone-code-sharing-httpwebrequest-getresponseasync/) but that caused the code to crash
Please point me in the right direction :)
Thnx Frank
What you're doing is only writing to the request stream. You're missing the code which reads from the response.
The reason you're getting back your request xml is that you reset the request stream and read from that exact stream.
Your method should look as follows:
private async Task DoCallWSAsync()
{
string url = "<my_url>";
// HTTP web request
var httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
httpWebRequest.ContentType = "text/xml";
httpWebRequest.Method = "POST";
// Write the request Asynchronously
using (var stream = await Task.Factory.FromAsync<Stream>(httpWebRequest.BeginGetRequestStream,
httpWebRequest.EndGetRequestStream, null))
{
string requestXml = "<my_request_xml>";
// convert request to byte array
byte[] requestAsBytes = Encoding.UTF8.GetBytes(requestXml);
// Write the bytes to the stream
await stream.WriteAsync(requestAsBytes , 0, requestAsBytes .Length);
}
using (WebResponse responseObject = await Task<WebResponse>.Factory.FromAsync(httpWebRequest.BeginGetResponse, httpWebRequest.EndGetResponse, httpWebRequest))
{
var responseStream = responseObject.GetResponseStream();
var sr = new StreamReader(responseStream);
string received = await sr.ReadToEndAsync();
return received;
}
}
I want to upload files from a Windows C# application to a web server running PHP.
I am aware of the WebClient.UploadFile method but I would like to be able to upload a file in chunks so that I can monitor progress and be able to pause/resume.
Therefore I am reading part of the file and using the WebClient.UploadData method.
The problem I am having is that I don't know how to access data sent with UploadData from php. If I do print_r on the post data I can see that there is binary data but I don't know the key to access it. How can I access the binary data? Is there a better way I should be doing this altogether?
String file = "C:\\Users\\Public\\uploadtest\\4.wmv";
using (BinaryReader b = new BinaryReader(File.Open(file, FileMode.Open)))
{
int pos = 0;
int required = 102400;
b.BaseStream.Seek(pos, SeekOrigin.Begin);
byte[] by = b.ReadBytes(required);
using (WebClient wc = new WebClient()){
wc.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
byte[] result = wc.UploadData("http://192.168.0.52/html/application.php", "POST", by);
String s = System.Text.Encoding.UTF8.GetString(result, 0, result.Length);
MessageBox.Show(s);
}
}
This is how I do my HTTP communications.
I guess when I reach using(), the HTTP connection is being set up, and inside the using() {...} body you can do pausing and stuff.
string valueString = "...";
string uriString = "http://someUrl/somePath";
HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(uriString);
httpWebRequest.Method = "POST";
string postData = "key=" + Uri.EscapeDataString(valueString);
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
httpWebRequest.ContentType = "application/x-www-form-urlencoded";
httpWebRequest.ContentLength = byteArray.Length;
using (Stream dataStream = httpWebRequest.GetRequestStream())
{
// do pausing and stuff here by using a while loop and changing byteArray.Length into the desired length of your chunks
dataStream.Write(byteArray, 0, byteArray.Length);
}
HttpWebResponse httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();
Stream receiveStream = httpWebResponse.GetResponseStream();
StreamReader readStream = new StreamReader(receiveStream);
string internalResponseString = readStream.ReadToEnd();
But when uploading a file, you should probably use multipart/form-data in stead of application/x-www-form-urlencoded. See also: http://www.php.net/manual/en/features.file-upload.post-method.php
In php you can use the superglobal variable $_FILES (eg print_r($_FILES); ) to access the uploaded file.
And also read this: https://stackoverflow.com/a/20000831/1209443 for more information how to deal with multipart/form-data
Use this. This will work for sure.
System.Net.WebClient Client = new System.Net.WebClient();
Client.Headers.Add("Content-Type", "binary/octet-stream");
byte[] result = Client.UploadFile("http://192.168.0.52/mipzy/html/application.php", "POST", file);
string s = System.Text.Encoding.UTF8.GetString(result, 0, result.Length);
MessageBox.Show(s);
Or the one with using
using (System.Net.WebClient Client = new System.Net.WebClient())
{
Client.Headers.Add("Content-Type", "binary/octet-stream");
byte[] result = Client.UploadFile("http://192.168.0.52/mipzy/html/application.php", "POST", file);
string s = System.Text.Encoding.UTF8.GetString(result, 0, result.Length);
MessageBox.Show(s);
}
Without binary reader. IF you want binary reader, you also must provide some multipart parameters to the form. This is automatically done by that UploadFile thing.
I'm passing the stream this way:
StreamReader sr = new StreamReader(openFileDialog1.FileName);
byte[] fileStream = Utility.ReadFully(sr.BaseStream);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(new Uri(baseAddress));
request.Method = "POST";
request.ContentType = "application/octet-stream";
Stream serverStream = request.GetRequestStream();
serverStream.Write(fileStream, 0, fileStream.Length);
serverStream.Close();
HttpWebResponse response2 = (HttpWebResponse)request.GetResponse();
if (response2.StatusCode == HttpStatusCode.OK)
{
MessageBox.Show(Utility.ReadResponse(response2));
}
-------------------------------------------------------------------------
public static byte[] ReadFully(Stream input)
{
byte[] buffer = new byte[16 * 1024];
using (MemoryStream ms = new MemoryStream())
{
if (input != null)
{
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
}
return ms.ToArray();
}
}
Then handling it on the server:
public bool UploadPhotoStream(string someStringParam, Stream fileData)
{
string filePath = string.Format("{0}/{1}", 'sdfgsdf87s7df8sd', '24asd54s4454d5f4g');
ProductPhoto newphoto = new ProductPhoto();
newphoto.FileSizeBytes = fileData.Length / 1024 / 1024;
newphoto.FileLocation = filePath;
...
}
Now I'm getting NotSupportedException when calling fileData.Length. I know it happens because the stream is closed. But how can I re-open it? Or what should I do so that when I pass the stream to the service I can still get its length?
Why don't you pass content-length header? Your server can check the header and know exactly how many bytes is the content being sent. How you read the header depends on which http framework you are using, ASP.NET Web Api, classic WCF Web Api, HttpListener, etc.
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(new Uri(baseAddress));
request.Method = "POST";
request.ContentType = "application/octet-stream";
request.ContentLength = new FileInfo(openFileDialog1.FileName).Length
Without a Content-Length header, an http server can never know how many bytes are left to read. All it knows is there is a Stream and will read it till there is no more data. This is also how your browser can display a progress bar when downloading something. It takes bytesDownloaded / Content-Length.
According to this post: https://stackoverflow.com/a/8239268/1160036
You can access the header like this from your web method.
long dataLength = long.Parse(HttpContext.Current.Request.Headers["Content-Length"]);
In C# rather than having to dowloading a file from the web using httpwebrequest, save this to file somewhere, and then upload to a webservice using a POST with the file as one of the parameters...
Can I instead somehow open a reader stream from httpwebresponse and then stream this into the http POST? Any code someone could post to show how?
In other words I'm trying to avoid haing to save to disk first.
Thanks
Something like that should do the trick :
HttpWebRequest downloadRequest = WebRequest.Create(downloadUri) as HttpWebRequest;
using(HttpWebResponse downloadResponse = downloadRequest.GetResponse() as HttpWebResponse)
{
HttpWebRequest uploadRequest = new HttpWebRequest(uploadUri);
uploadRequest.Method = "POST";
uploadRequest.ContentLength = downloadResponse.ContentLength;
using (Stream downloadStream = downloadResponse.GetResponseStream())
using (Stream uploadStream = uploadRequest.GetRequestStream())
{
byte[] buffer = new byte[4096];
int totalBytes = 0;
while(totalBytes < downloadResponse.ContentLength)
{
int nBytes = downloadStream.Read(buffer, 0, buffer.Length);
uploadStream.Write(buffer, 0, nBytes);
totalBytes += nRead;
}
}
HttpWebResponse uploadResponse = uploadRequest.GetResponse() as HttpWebResponse;
uploadResponse.Close();
}
(untested code)
I'm trying to send a file in chunks to an HttpHandler but when I receive the request in the HttpContext, the inputStream is empty.
So a: while sending I'm not sure if my HttpWebRequest is valid
and b: while receiving I'm not sure how to retrieve the stream in the HttpContext
Any help greatly appreciated!
This how I make my request from client code:
private void Post(byte[] bytes)
{
HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create("http://localhost:2977/Upload");
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.SendChunked = true;
req.Timeout = 400000;
req.ContentLength = bytes.Length;
req.KeepAlive = true;
using (Stream s = req.GetRequestStream())
{
s.Write(bytes, 0, bytes.Length);
s.Close();
}
HttpWebResponse res = (HttpWebResponse)req.GetResponse();
}
this is how I handle the request in the HttpHandler:
public void ProcessRequest(HttpContext context)
{
Stream chunk = context.Request.InputStream; //it's empty!
FileStream output = new FileStream("C:\\Temp\\myTempFile.tmp", FileMode.Append);
//simple method to append each chunk to the temp file
CopyStream(chunk, output);
}
I suspect it might be confusing that you are uploading it as form-encoded. but that isn't what you are sending (unless you're glossing over something). Is that MIME type really correct?
How big is the data? Do you need chunked upload? Some servers might not like this in a single request; I'd be tempted to use multiple simple requests via WebClient.UploadData.
i was trying the same idea and was successfull in sending file through Post httpwebrequest. Please see the following code sample
private void ChunkRequest(string fileName,byte[] buffer)
{
//Request url, Method=post Length and data.
string requestURL = "http://localhost:63654/hello.ashx";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestURL);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
// Chunk(buffer) is converted to Base64 string that will be convert to Bytes on the handler.
string requestParameters = #"fileName=" + fileName +
"&data=" + HttpUtility.UrlEncode( Convert.ToBase64String(buffer) );
// finally whole request will be converted to bytes that will be transferred to HttpHandler
byte[] byteData = Encoding.UTF8.GetBytes(requestParameters);
request.ContentLength = byteData.Length;
Stream writer = request.GetRequestStream();
writer.Write(byteData, 0, byteData.Length);
writer.Close();
// here we will receive the response from HttpHandler
StreamReader stIn = new StreamReader(request.GetResponse().GetResponseStream());
string strResponse = stIn.ReadToEnd();
stIn.Close();
}
I have blogged about it, you see the whole HttpHandler/HttpWebRequest post here
http://aspilham.blogspot.com/2011/03/file-uploading-in-chunks-using.html
I hope this will help