67

I have a WebApi service handling an upload from a simple form, like this one:

    <form action="/api/workitems" enctype="multipart/form-data" method="post">
        <input type="hidden" name="type" value="ExtractText" />
        <input type="file" name="FileForUpload" />
        <input type="submit" value="Run test" />
    </form>

However, I can't figure out how to simulate the same post using the HttpClient API. The FormUrlEncodedContent bit is simple enough, but how do I add the file contents with the name to the post?

Cheeso
  • 189,189
  • 101
  • 473
  • 713
Michael Teper
  • 4,591
  • 2
  • 32
  • 49

3 Answers3

134

After much trial and error, here's code that actually works:

using (var client = new HttpClient())
{
    using (var content = new MultipartFormDataContent())
    {
        var values = new[]
        {
            new KeyValuePair<string, string>("Foo", "Bar"),
            new KeyValuePair<string, string>("More", "Less"),
        };

        foreach (var keyValuePair in values)
        {
            content.Add(new StringContent(keyValuePair.Value), keyValuePair.Key);
        }

        var fileContent = new ByteArrayContent(System.IO.File.ReadAllBytes(fileName));
        fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
        {
            FileName = "Foo.txt"
        };
        content.Add(fileContent);

        var requestUri = "/api/action";
        var result = client.PostAsync(requestUri, content).Result;
    }
}
Brijesh Mishra
  • 2,738
  • 1
  • 21
  • 36
Michael Teper
  • 4,591
  • 2
  • 32
  • 49
  • 23
    Use StreamContent for large files: var fileContent = new StreamContent(File.OpenRead(fileName)); – Jalal El-Shaer Jun 03 '12 at 22:16
  • Woohoo -- I had a totally different issue, but needed to post content nonetheless. I was able to modify to fit my needs. Thanks a lot!! – Matthew Pitts Oct 28 '12 at 07:36
  • 3
    Strangely this does not work for me. I had to add quotes around the content names, see this: http://stackoverflow.com/questions/15638622/how-to-upload-files-to-asp-net-mvc-4-0-action-running-in-iis-express-with-httpcl/15638623#15638623 – deerchao Mar 27 '13 at 08:53
  • @deerchao I think the difference is in how you process the post on the back-end. In my case, I was using WebApi and `MultipartFormDataStreamProvider`. – Michael Teper Mar 27 '13 at 14:35
  • 6
    FYI, there is a constant for "attachment" under System.Net.Mime.DispositionTypeNames – Robert Jan 10 '15 at 23:47
  • 2
    I too had to add quotes around the name value: FileName = "\"TestImage.jpg\"". I am using ServiceStack on the server instead of WebAPI not sure if that is related or not. – Rob Bird Jan 30 '15 at 20:56
  • I keep getting `StatusCode: 415, ReasonPhrase: 'Unsupported Media Type'`, any ideas ? – djack109 Apr 23 '20 at 18:17
14

Thank you @Michael Tepper for your answer.

I had to post attachments to MailGun (email provider) and I had to modify it slightly so it would accept my attachments.

var fileContent = new ByteArrayContent(System.IO.File.ReadAllBytes(fileName));
fileContent.Headers.ContentDisposition = 
        new ContentDispositionHeaderValue("form-data") //<- 'form-data' instead of 'attachment'
{
    Name = "attachment", // <- included line...
    FileName = "Foo.txt",
};
multipartFormDataContent.Add(fileContent);

Here for future reference. Thanks.

ThiagoPXP
  • 5,362
  • 3
  • 31
  • 44
11

You need to look for various subclasses of HttpContent.

You create a multiform http content and add various parts to it. In your case you have a byte array content and form url encoded along the lines of:

HttpClient c = new HttpClient();
var fileContent = new ByteArrayContent(new byte[100]);
fileContent.Headers.ContentDisposition 
  = new ContentDispositionHeaderValue("attachment")
{
  FileName = "myFilename.txt"
};

var formData = new FormUrlEncodedContent(new[]
{
  new KeyValuePair<string, string>("name", "ali"),
  new KeyValuePair<string, string>("title", "ostad")
}); 
        
MultipartContent content = new MultipartContent();
content.Add(formData);
content.Add(fileContent);
c.PostAsync(myUrl, content);
Konrad Viltersten
  • 36,151
  • 76
  • 250
  • 438
Aliostad
  • 80,612
  • 21
  • 160
  • 208
  • 1
    That doesn't work, unfortunately, although the `ContentDisposition` header does seems to take me a step forward. If I use your sample code as is, I get an `Unsupported Media Type` exception. However, if I replace `MultipartContent` with `MultipartFormDataContent` the exception goes away. On the server, however, the value of the hidden field is missing. – Michael Teper Apr 26 '12 at 22:42
  • @MichaelTeper I have not tested the code. I will play a bit with it and update the post, but my point was to show you a snippet of what you need to look for and not a working code. – Aliostad Apr 27 '12 at 00:06
  • I just get `StatusCode: 415, ReasonPhrase: 'Unsupported Media Type'` – djack109 Apr 23 '20 at 18:17