Search code examples
c#jsonweb-servicesclienthttpclient

POST result empty after passing a JSON string along with a file


I'm encountering an issue uploading a file (image for this example) along with a JSON string. I am as the client, trying to upload to a webserver. Currently on the website itself, when uploading a file, the payload is this:

------WebKitFormBoundary1A4Toq4hnrayCRu4
Content-Disposition: form-data; name="FileInstance"

{"action":["/public/my_folder"],"fileName":"download_icon.png","fileSize":313,"certification":{"level":"0","Groups":[]}}

------WebKitFormBoundary1A4Toq4hnrayCRu4
Content-Disposition: form-data; name="download_icon.png"; filename="download_icon.png"
Content-Type: image/png


------WebKitFormBoundary1A4Toq4hnrayCRu4--

I am POSTing by 2 separate requests, and each result has a 200 status code, but looking into the result, it's empty and I should be receiving an md5hash of the file uploaded but I am not.

Here is my code:

// Uploading the JSON first
MultipartFormDataContent form = new MultipartFormDataContent();
var boundary = $"----WebKitFormBoundary" + DateTime.Now.Ticks.ToString("x");
form.Headers.Remove("Content-Type");
form.Headers.Add("Content-Type", $"multipart/form-data; boundary={boundary}");
MyFileClass currentFile = new MyFileClass();
currentFile.action = new List<string>() { "/public/my_folder" };
currentFile.filename = Path.GetFileName(Filename);

currentFile.fileSize = Convert.ToInt32(new FileInfo(Filename).Length);

currentFile.certification= new MyFileClass.Certification();
CreateCertification(currentFile.certification);

var json = JsonConvert.SerializeObject(currentFile);
HttpContent content = new StringContent(json, Encoding.UTF8, "application/json");
content.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
     Name = Path.GetFileName(Filename),
     FileName = Path.GetFileName(Filename)
};
var response = await myHttpClient.PostAsync(url, form);
var result_str = response.Content.ReadAsStringAsync().Result;

// Uploading the actual file

var stream = new FileStream(Filename, FileMode.Open);
form = new MultipartFormDataContent();
boundary = $"----WebKitFormBoundary" + DateTime.Now.Ticks.ToString("x");
form.Headers.Remove("Content-Type");
form.Headers.Add("Content-Type", $"multipart/form-data; boundary={boundary}");
content = new StreamContent(stream);
content.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
     {
          Name = "FileInstance"
     };
content = new StreamContent(stream);
form.Add(content, Path.GetFileNameWithoutExtension(Filename));

response = await myHttpClient.PostAsync(url, form);
result_str = response.Content.ReadAsStringAsync().Result;

Edit 1: This is how httpclient is defined:

string password = SecureStringExtensions.ToUnsecuredString(Password);
var credCache = new CredentialCache
{
     { 
          new Uri(url), "Basic", new NetworkCredential(Username, password) 
     }
};

var myHttpClient = new HttpClient(new HttpClientHandler() { Credentials = credCache });
myHttpClient.DefaultRequestHeaders.Add("Connection", "keep-alive");
myHttpClient.Timeout = Timeout.InfiniteTimeSpan;

Solution

  • I was trying different methods of POSTing which didn't work. Now I found a solution, where I removed editing the boundary and ContentType, and straight forward added the file and JSON at the same time to MultipartFormDataContent and it worked fine.

    MyFileClass currentFile = new MyFileClass();
    currentFile.action = new List<string>() { "/public/my_folder" };
    currentFile.filename = Path.GetFileName(Filename);
    
    currentFile.fileSize = Convert.ToInt32(new FileInfo(Filename).Length);
    
    currentFile.certification= new MyFileClass.Certification();
    CreateCertification(currentFile.certification);
    
    var json = JsonConvert.SerializeObject(currentFile);
    
    var formContent = new MultipartFormDataContent
    {
         { new StringContent(json, Encoding.UTF8, "application/json") },
         { new StreamContent(new MemoryStream(File.ReadAllBytes(Filename))), Path.GetFileName(Filename) ,Path.GetFileName(Filename)}
    };
    
    var response = await myHttpClient.PostAsync(url, formContent);
    string stringContent = await response.Content.ReadAsStringAsync();
    

    Where Filename is the absolute path of the file itself.