-2

I hate this API.... The documentation states:

POST /api/2/path/data/Documents/ HTTP/1.1

Content-Type: multipart/form-data

Content-Length: length of request body here

multi-part data here

So I created this:

    public async Task<bool> UploadAsync(string path, string fileName, byte[] data)
    {
        EnforceBasicAuthentication();
        var byteContent = new ByteArrayContent(data);
        byteContent.Headers.Remove("Content-Type");
        byteContent.Headers.Add("Content-Type", "multipart/form-data");
        byteContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
        {
            FileName = fileName,
            Name = "file"
        };
        var form = new MultipartFormDataContent
        {
            byteContent
        };
        var response = await _httpClient.PostAsync($"{_config.FtpUrl}/path/data/{_config.FtpPath}/{path}", form);
        response.EnsureSuccessStatusCode();
        return true;
    }

But every time I run it, I get a 400 bad request error. It doesn't say anything other than that. Looking at my code, is there anything that looks wrong?


I have tried multiple solutions and none of them seem to work. Currently I have this:

public async Task<bool> UploadAsync(string path, string fileName, byte[] data)
{
    EnforceBasicAuthentication();

    var boundary = "--------------------------" + DateTime.Now.Ticks.ToString("x");
    var bytesContent = new ByteArrayContent(data);
    var form = new MultipartFormDataContent();

    form.Add(bytesContent, "file", fileName);
    form.Headers.Remove("Content-Type");
    form.Headers.TryAddWithoutValidation("Content-Type", $"multipart/form-data; boundary= { boundary }");
    bytesContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/octet-stream");

    var response = await _httpClient.PostAsync($"{_config.FtpUrl}/path/data/{_config.FtpPath}/{path}", form);
    response.EnsureSuccessStatusCode();
    return true;
}

But it still throws a 400 error. I have configured Fiddler and done a test in postman. The test in postman worked fine. Here is the request in fiddler:

POST https://app.smartfile.com/api/2/path/data/eOrdering/GRE017 HTTP/1.1

cache-control: no-cache

Postman-Token: 8359aae8-f4e2-4864-b81a-0169fe3f2b62

Authorization: Basic bleh

User-Agent: PostmanRuntime/7.1.1

Accept: /

Host: app.smartfile.com

cookie: csrftoken=rsDaPbfwG070rwBFlhIWVvULcAqGW0GB;

sessionid=a744788776bfef3c44faf6eb5e2a2931

accept-encoding: gzip, deflate

content-type: multipart/form-data; boundary=--------------------------606952503302468487113354

content-length: 334

Connection: close

----------------------------606952503302468487113354

Content-Disposition: form-data; name=""; filename="S200-220311-20180606095501.ord"

Content-Type: application/octet-stream

274 274/1 |PAULA|00220311|STD|||ASAP

1|23133|1313 131302 4.00|C|3.65|||12/06/18

----------------------------606952503302468487113354--

And this is the one generated by my code:

POST https://app.smartfile.com/api/2/path/data/eOrdering/GRE017 HTTP/1.1

Authorization: Basic blah

Content-Type: multipart/form-data; boundary=--------------------------8d5d140cf824278

Host: app.smartfile.com

Cookie: csrftoken=NYOgu61I6ddqBgudQEhWNr27fJUEQFi3;

sessionid=6994ad9254ebc46e0611e6ac308d6c55

Content-Length: 375

--52343329-f101-43a2-b4bb-bfa9a4073f6e

Content-Disposition: form-data; name=file; filename=3c3f1596-707b-4725-9766-25faf6124a35.rsl; filename*=utf-8''3c3f1596-707b-4725-9766-25faf6124a35.rsl

Content-Type: application/octet-stream

Fail|"Price Issue Number is invalid, must be greater than 0"|

1|23133|01/01/0001 00:00:00|0|0

--52343329-f101-43a2-b4bb-bfa9a4073f6e--

I still have no idea why it is failing :(

Community
  • 1
  • 1
r3plica
  • 13,017
  • 23
  • 128
  • 290
  • Possible duplicate of [C# HttpClient 4.5 multipart/form-data upload](https://stackoverflow.com/questions/16416601/c-sharp-httpclient-4-5-multipart-form-data-upload) – mjwills Jun 13 '18 at 13:01
  • 1
    Also verify and mayb post that url + query. Can you use PostMan? – bommelding Jun 13 '18 at 13:17

2 Answers2

1

So, I figured this out after spending ages on it. There are two issues that needed to be addressed. The first one was the double fileName (which also had no double quotes around them) and the second was the boundary.... In the end, I changed my code to look like this:

public async Task<bool> UploadAsync(string path, string fileName, byte[] data)
{
    EnforceBasicAuthentication();
    var bytesContent = new ByteArrayContent(data);
    bytesContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/octet-stream");
    bytesContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
    {
        Name = "\"file\"",
        FileName = $"\"{fileName}\""
    };
    var formData = new MultipartFormDataContent { bytesContent };
    var boundary = formData.Headers.ContentType.Parameters.First(o => o.Name == "boundary");
    boundary.Value = boundary.Value.Replace("\"", string.Empty);
    var response = await _httpClient.PostAsync($"{_config.FtpUrl}/path/data/{_config.FtpPath}/{path}", formData);
    response.EnsureSuccessStatusCode();
    return true;
}

As you can see there, for the ContentDisposition I added the name and filename (with \" because of a bug....) and for the FormData content type, I had to remove the extra double quotes.

Really annoying, but finally working....

r3plica
  • 13,017
  • 23
  • 128
  • 290
-1

Try your byte data into var content = new ByteArrayContent(filedata); and pass content to PostAsync something like below:

var content = new ByteArrayContent(data);
var ApiRequest = client.PostAsync(apiUrl, content);
Dashrath
  • 79
  • 9