Upload Any File Using HTTP Post Multipart Form Data

In this article, we will discuss how to upload any file using HTTP Post multipart/form-data in C#. I have tried my best to explain the use of the code described for multipart/form-data post needed many times while working with API’s in C#. I hope this would be helpful in the situations where we need to upload any file or image to the server using post method in C#.

In this article, we will discuss how to upload any file using HTTP Post multipart/ form-data in C#. I have tried my best to explain the use of the code needed for multipart/form-data posts many times while working with APIs in C#. I hope this will be helpful in situations where we need to upload any file or image to the server using the post method in C#.

Requirement

There might be a situation that you will have to write code to post your file to the server through C# code without using any HTML form page. Suppose you have some images on your server and you want to post those to any third-party API through the C# application. You can achieve that through the following code.

Here are the steps to be followed.

Step 1

Create a new application in .NET, it could be either web or console application according to your requirement. Skip this step if you want to use  the existing project. 

Step 2

Create a new class with the following code. You can create this class at any common place from where you can access it easily.

  1. public static class FormUpload  
  2.     {  
  3.         private static readonly Encoding encoding = Encoding.UTF8;  
  4.         public static HttpWebResponse  MultipartFormPost(string postUrl, string userAgent, Dictionary<string, object> postParameters, string headerkey, string headervalue)  
  5.         {  
  6.             string formDataBoundary = String.Format("----------{0:N}", Guid.NewGuid());  
  7.             string contentType = "multipart/form-data; boundary=" + formDataBoundary;  
  8.   
  9.             byte[] formData = GetMultipartFormData(postParameters, formDataBoundary);  
  10.   
  11.             return PostForm(postUrl, userAgent, contentType, formData, headerkey, headervalue);  
  12.         }  
  13.         private static HttpWebResponse PostForm(string postUrl, string userAgent, string contentType, byte[] formData, string headerkey, string headervalue)  
  14.         {  
  15.             HttpWebRequest request = WebRequest.Create(postUrl) as HttpWebRequest;  
  16.   
  17.             if (request == null)  
  18.             {  
  19.                 throw new NullReferenceException("request is not a http request");  
  20.             }  
  21.   
  22.             // Set up the request properties.  
  23.             request.Method = "POST";  
  24.             request.ContentType = contentType;  
  25.             request.UserAgent = userAgent;  
  26.             request.CookieContainer = new CookieContainer();  
  27.             request.ContentLength = formData.Length;  
  28.   
  29.             // You could add authentication here as well if needed:  
  30.             // request.PreAuthenticate = true;  
  31.             // request.AuthenticationLevel = System.Net.Security.AuthenticationLevel.MutualAuthRequested;  
  32.   
  33. //Add header if needed  
  34.             request.Headers.Add(headerkey, headervalue);  
  35.   
  36.             // Send the form data to the request.  
  37.             using (Stream requestStream = request.GetRequestStream())  
  38.             {  
  39.                 requestStream.Write(formData, 0, formData.Length);  
  40.                 requestStream.Close();  
  41.             }  
  42.   
  43.             return request.GetResponse() as HttpWebResponse;  
  44.         }  
  45.   
  46.         private static byte[] GetMultipartFormData(Dictionary<string, object> postParameters, string boundary)  
  47.         {  
  48.             Stream formDataStream = new System.IO.MemoryStream();  
  49.             bool needsCLRF = false;  
  50.   
  51.             foreach (var param in postParameters)  
  52.             {  
  53.                   
  54.                 if (needsCLRF)  
  55.                     formDataStream.Write(encoding.GetBytes("\r\n"), 0, encoding.GetByteCount("\r\n"));  
  56.   
  57.                 needsCLRF = true;  
  58.   
  59.                 if (param.Value is FileParameter) // to check if parameter if of file type   
  60.                 {  
  61.                     FileParameter fileToUpload = (FileParameter)param.Value;  
  62.   
  63.                     // Add just the first part of this param, since we will write the file data directly to the Stream  
  64.                     string header = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"; filename=\"{2}\"\r\nContent-Type: {3}\r\n\r\n",  
  65.                         boundary,  
  66.                         param.Key,  
  67.                         fileToUpload.FileName ?? param.Key,  
  68.                         fileToUpload.ContentType ?? "application/octet-stream");  
  69.   
  70.                     formDataStream.Write(encoding.GetBytes(header), 0, encoding.GetByteCount(header));  
  71.   
  72.                     // Write the file data directly to the Stream, rather than serializing it to a string.  
  73.                     formDataStream.Write(fileToUpload.File, 0, fileToUpload.File.Length);  
  74.                 }  
  75.                 else  
  76.                 {  
  77.                     string postData = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"\r\n\r\n{2}",  
  78.                         boundary,  
  79.                         param.Key,  
  80.                         param.Value);  
  81.                     formDataStream.Write(encoding.GetBytes(postData), 0, encoding.GetByteCount(postData));  
  82.                 }  
  83.             }  
  84.   
  85.             // Add the end of the request.  Start with a newline  
  86.             string footer = "\r\n--" + boundary + "--\r\n";  
  87.             formDataStream.Write(encoding.GetBytes(footer), 0, encoding.GetByteCount(footer));  
  88.   
  89.             // Dump the Stream into a byte[]  
  90.             formDataStream.Position = 0;  
  91.             byte[] formData = new byte[formDataStream.Length];  
  92.             formDataStream.Read(formData, 0, formData.Length);  
  93.             formDataStream.Close();  
  94.   
  95.             return formData;  
  96.         }  
  97.   
  98.         public class FileParameter  
  99.         {  
  100.             public byte[] File { get; set; }  
  101.             public string FileName { get; set; }  
  102.             public string ContentType { get; set; }  
  103.             public FileParameter(byte[] file) : this(file, null) { }  
  104.             public FileParameter(byte[] file, string filename) : this(file, filename, null) { }  
  105.             public FileParameter(byte[] file, string filename, string contenttype)  
  106.             {  
  107.                 File = file;  
  108.                 FileName = filename;  
  109.                 ContentType = contenttype;  
  110.             }  
  111.         }  
  112.     }  

In this class, we have three methods.

MultipartFormPost

This method has five parameters. You can increase/decrease the number of parameters according to your requirement. These five parameters are, 
  • Posturl 
    This must be the url to which you want to post the form.
  • userAgent
    This is up to your requirement; if needed, then pass the value as required.
  • postParameters
    This is of type Dictionary. You can pass the parameter name and value as “key-value”
  • headerkey
    This must be the name of the header that needs to be passed. In this example, I have used it as a string which can be used to pass a single header. If the header is not required, you can ignore this parameter.
  • headervalue
    This must be the value of the header to be passed.

If your request requires multiple headers you can use Dictionary for the header as we used for parameters. In that case, instead of headerkey and headervalue parameters, you will have to use a single parameter of type Dictionary.

 Ex- Dictionary<string,string> Headers

Here header name and value will be passed as a key-value pair.

GetMultipartFormData

This method will give you form data in byte form to post. 

PostForm

This is a private method and will be called within the public method, MultipartFormPost. This method has two other parameters, contentType and formData. We have added static content type while we got formData from GetMultipartFormData. 

I have also created a class named FileParameter with some class members and constructor to use directly while passing a file as a parameter to my post method.

Step 3

Write the below code section from where you want to call the multipart-post method. The code line byte[] bytes = wc.DownloadData(fileName); is used to download the file if your file is on the server otherwise you can convert that file directly to bytes if it exists locally. I have passed a parameter named “fileToUpload”, this is of type class FileParameter. You can pass the name and number of parameters according to your requirement.

  1. try {  
  2.     string requestURL = ”your url to post”;  
  3.     string fileName = ”URL of your file”  
  4.     WebClient wc = new WebClient();  
  5.     byte[] bytes = wc.DownloadData(fileName); // You need to do this download if your file is on any other server otherwise you can convert that file directly to bytes  
  6.     Dictionary < string, object > postParameters = new Dictionary < string, object > ();  
  7.     // Add your parameters here  
  8.     postParameters.Add("fileToUpload"new FormUpload.FileParameter(bytes, Path.GetFileName(fileName), "image/png"));  
  9.     string userAgent = "Someone";  
  10.     HttpWebResponse webResponse = FormUpload.MultipartFormDataPost(requestURL, userAgent, postParameters, headerkey, headervalue);  
  11.     // Process response  
  12.     StreamReader responseReader = new StreamReader(webResponse.GetResponseStream());  
  13.     returnResponseText = responseReader.ReadToEnd();  
  14.     webResponse.Close();  
  15. catch (Exception exp) {}