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();

Related posts

About Clivant

Clivant a.k.a Chai Heng enjoys composing software and building systems to serve people. He owns techcoil.com and hopes that whatever he had written and built so far had benefited people. All views expressed belongs to him and are not representative of the company that he works/worked for.

18 Comments

  • jibin
    July 22, 2011 at 7:01 pm

    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

    • clivant
      July 23, 2011 at 10:02 am

      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.

      • JIBIN
        July 27, 2011 at 3:26 pm

        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

        • clivant
          July 28, 2011 at 2:27 am

          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. 🙂

          • Sani
            April 9, 2012 at 5:43 am

            Keep on wrtiing and chugging away!

          • clivant
            April 9, 2012 at 9:35 am

            Thanks Sani! 🙂

  • ketchup
    January 12, 2013 at 12:50 am

    link is broken for “Uploading large HTTP multipart request with System.Net.HttpWebRequest in C#”

    • Clivant
      January 12, 2013 at 7:23 pm

      Hi Ketchup,

      Thanks for the information. I had updated the link.

  • Ivan Schneider
    April 10, 2013 at 3:13 am

    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.

    • Clivant
      May 11, 2013 at 9:12 pm

      Hi Ivan,

      I had included the relevant codes to get the server response.

  • blanze
    July 12, 2013 at 2:04 pm

    Hi Sir, Could you please help me on how to upload files in the ftp server? using HTTP.

    • Clivant
      August 23, 2013 at 11:34 pm

      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.

  • Rafael Gil
    August 8, 2013 at 1:55 am

    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.

    • Clivant
      September 22, 2013 at 7:59 am

      Hi Rafael,

      Thanks for dropping by. You can take a look at his post for more information on GetPostRequest.php.

  • Will Huo
    September 29, 2013 at 10:01 am

    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.

    • Clivant
      September 29, 2013 at 11:24 am

      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.

  • Sara
    July 3, 2014 at 2:00 pm

    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.

    • Clivant
      July 8, 2014 at 11:08 am

      Hi Sara,

      Thank you for your encouragements! 🙂