Sending a file and some form data via HTTP post in C#
A few weeks back, I wrote some logic to send a file and a from a windows client over to a Java server endpoint. There are a few ways to do that: via application protocols like FTP and HTTP or even implementing a custom protocol using TCP/IP. Since the Java server was already serving HTTP requests and that HTTP requests can usually get through firewalls quite easily, I chose the HTTP protocol.
Figuring out the HTTP request
The first step to writing the logic was simple - to see how browsers form a HTTP post request. With that, I started by constructing the following html form:
<html> <body> <form action="http://ipv4.fiddler/test/GetPostRequest.php" method="post" enctype="multipart/form-data"> <p> <strong>My file description:</strong> <textarea name="myFileDescription" rows="2" cols="20"> </textarea><br/> <br/> <strong>My file:</strong><br/> <input type="file" name="myFile"> </p> <input type="submit" value = "Submit"> </form> </body> </html>
And using Fiddler, I was able to get the following HTTP post request that was sent by my browser to my php script, after I submitted a form input.
POST http://127.0.0.1/GetPostRequest.php
HTTP/1.1 Host: 127.0.0.1
Connection: keep-alive
Referer: http://localhost/GetPostRequest.php
Content-Length: 1611568
Cache-Control: max-age=0
Origin: http://localhost
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.91 Safari/534.30
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryX6nBO7q27yQ1JNbb
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
------WebKitFormBoundaryX6nBO7q27yQ1JNbb
Content-Disposition: form-data; name="myFileDescription"
My sample file description.
------WebKitFormBoundaryX6nBO7q27yQ1JNbb
Content-Disposition: form-data; name="myFile"; filename="SomeRandomFile.pdf"
Content-Type: application/pdf
file contents...
------WebKitFormBoundaryX6nBO7q27yQ1JNbb--
Constructing the HTTP post request in C#
With the HTTP request constructed by my browser, constructing the HTTP post request in C# became very straightforward. There are classes from the System.Net and System.IO libraries that can be used for the generating and sending the request over to the server endpoint. The following is a proof of concept that I did for my actual solution:
// Create a http request to the server endpoint that will pick up the // file and file description. HttpWebRequest requestToServerEndpoint = (HttpWebRequest)WebRequest.Create("http://localhost/GetPostRequest.php"); string boundaryString = "----SomeRandomText"; string fileUrl = @"C:\SomeRandomFile.pdf"; // Set the http request header \\ requestToServerEndpoint.Method = WebRequestMethods.Http.Post; requestToServerEndpoint.ContentType = "multipart/form-data; boundary=" + boundaryString; requestToServerEndpoint.KeepAlive = true; requestToServerEndpoint.Credentials = System.Net.CredentialCache.DefaultCredentials; // Use a MemoryStream to form the post data request, // so that we can get the content-length attribute. MemoryStream postDataStream = new MemoryStream(); StreamWriter postDataWriter = new StreamWriter(postDataStream); // Include value from the myFileDescription text area in the post data postDataWriter.Write("\r\n--" + boundaryString + "\r\n"); postDataWriter.Write("Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}", "myFileDescription", "A sample file description"); // Include the file in the post data postDataWriter.Write("\r\n--" + boundaryString + "\r\n"); postDataWriter.Write("Content-Disposition: form-data;" + "name=\"{0}\";" + "filename=\"{1}\"" + "\r\nContent-Type: {2}\r\n\r\n", "myFile", Path.GetFileName(fileUrl), Path.GetExtension(fileUrl)); postDataWriter.Flush(); // Read the file FileStream fileStream = new FileStream(fileUrl, FileMode.Open, FileAccess.Read); byte[] buffer = new byte[1024]; int bytesRead = 0; while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0) { postDataStream.Write(buffer, 0, bytesRead); } fileStream.Close(); postDataWriter.Write("\r\n--" + boundaryString + "--\r\n"); postDataWriter.Flush(); // Set the http request body content length requestToServerEndpoint.ContentLength = postDataStream.Length; // Dump the post data from the memory stream to the request stream using (Stream s = requestToServerEndpoint.GetRequestStream()) { postDataStream.WriteTo(s); } postDataStream.Close();
Getting the response from the server
We get the server response by reading from the System.Net.WebResponse instance, that can be retrieved via the HttpWebRequest.GetResponseStream() method.
// Grab the response from the server. WebException will be thrown // when a HTTP OK status is not returned WebResponse response = requestToServerEndpoint.GetResponse(); StreamReader responseReader = new StreamReader(response.GetResponseStream()); string replyFromServer = responseReader.ReadToEnd();
18 Comments
Hi, i tried the code mentioned here and its not working for me
i got the error or exception
{“The underlying connection was closed: An unexpected error occurred on a receive.”}
{“Unable to read data from the transport connection: An established connection was aborted by the software in your host machine.”}
at the line of request.GetResponse()
I disable antivirus, firewall on my system and still i rxv same error. Any method to solve this error.
Can you please suggest a way to get out from this error
Jibin.mn@gmail.com
Hi jibin,
I assume that your C# client is not residing in the same machine as your server. Are you running your client and server in your own network or in a corporate network?
Most corporate networks do not allow their IP addresses to host programs. That may be one reason why you encounter the error.
Hi , you are right , i am trying to upload the files from a desktop application to a remote server and i am able to send small files say max of 2MB.But if i try to post some large files it returns time out exception.
To solve this error what are the settings need to change on remote server or any other good approaches.(i want to upload files of 250 MB)
Thanks
Hi,
Most servers / server programming language implement a size restriction on uploaded files, which can be configured.
For instance, to configure php to accept a larger upload file, you can change the value for the “upload_max_filesize” directive in the php.ini file.
I am not sure what is the make for your remote server. I would suggest that you do a search with the keywords “change maximum upload file size” together with the name of the server or server programming language that you are using.
Hope it helps. 🙂
Keep on wrtiing and chugging away!
Thanks Sani! 🙂
link is broken for “Uploading large HTTP multipart request with System.Net.HttpWebRequest in C#”
Hi Ketchup,
Thanks for the information. I had updated the link.
Hello. Sorry for my bad English. I am Brazilian.
How do I get the return after sending the file?
The sending worked, but do not know how to get the return.
Thank you.
Hi Ivan,
I had included the relevant codes to get the server response.
Hi Sir, Could you please help me on how to upload files in the ftp server? using HTTP.
Hi Blanze,
You will have to install a web server at the machine which the ftp server resides on. Alternatively, you can code one with C#’s System.Net.HttpListener class. You can check out how to do so in this post.
Hi Clivant, could you please share the GetPostRequest.php file code?
I’m interested on the part where you handle the uploaded file and move it to a custom folder in the server.
Thanks in advace.
Hi Rafael,
Thanks for dropping by. You can take a look at his post for more information on GetPostRequest.php.
Hi Clivant.
I am developing a test to post larger data to a HTTP server. And I know the data as the type of multipart/form-data should be formed as the specified type.
So I write the code like yours but I had changed some parts of it to adapt to the current stream form.
But I always get the failed response like “user error”. The test code is ok but I do not know the mistake. The website is HTTPS not HTTP.
Hi Will,
I suspect that your client may have encountered a out of memory error, that was why the server responded with the “user error”.
I encountered out of memory with this set of coding in sending large data. To workaround, I construct and send the HTTP request directly to the HttpWebRequest instance instead of first sending the HTTP request to a MemoryStream instance.
You can check out how I do that in this post.
Dear Clivant,
I’m impressed by your knowledge and willingness to share it with other people. Just keep on doing things that suit you so well! 🙂
Warm greetings from Europe.
Hi Sara,
Thank you for your encouragements! 🙂