0

I am writing a program which needs to use a RESTful API to upload files. The documentation provided only covers uploading using cURL. The sample cURL command from the documentation looks like this:

curl -X POST ^
-u ${username}:${password} ^
-H "Content-Type: application/octet-stream" ^
-H "Content-Disposition: ${file_name}" ^
-T "${file_path}" ^
-1 -k ^
--url "https://${app_server}/stream/v1/files?projectid=${projectid}"

I wrote the following methods attempting to simulate that behavior:

internal static async Task<string> Post(string filePath)
{
    string fileName = new FileInfo(filePath).Name;
    MemoryStream Content = ToStream(filePath);

    using (var httpClient = new HttpClient())
    {
        httpClient.BaseAddress = new Uri(Context.RESTUrl);
        httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(@"Basic", Context.EncodedAuthHeader);
        HttpRequestMessage httpRequest = new HttpRequestMessage(HttpMethod.Post, Context.RESTUrl);
        httpRequest.Content = new StreamContent(Content);
        httpRequest.Content.Headers.ContentType = new MediaTypeHeaderValue(Constants.ContentType);

        //This is my best-guess for [-H "Content-Disposition: ${file_name}"]
        httpRequest.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue(@"form-data")
        {
            Name = "fileUpload",
            FileName = fileName
        };

        var response = httpClient.SendAsync(httpRequest).Result;
        validResponse = response.StatusCode == HttpStatusCode.Created;

        var contents = await response.Content.ReadAsStringAsync();
        return contents;
    }
}

In terms of -T "${file_path}" I'm assuming (maybe erroneously) that cURL is converting the file contents into something that can actually travel via TCP packets (a byte array), so I am passing the file as a MemoryStream in the content of the HttpRequest. Here's how I'm converting the file to a memory stream:

internal static MemoryStream ToStream(string filePath)
{
    MemoryStream Result = new MemoryStream();
    using (FileStream fStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
    {
        fStream.CopyTo(Result);
    }
    return Result;
}

The API returns a positive result, however, when I log onto the portal, although I do see the file I uploaded, the file length is 0 bytes, so I'm assuming that:

httpRequest.Content = new StreamContent(Content);

Is being ignored.

Any advice would be greatly appreciated!

Mike Bruno
  • 600
  • 2
  • 9
  • 26
  • 2
    You can check this https://stackoverflow.com/a/16595979/1543596 answer. – Ygalbel Jul 02 '20 at 13:26
  • 2
    or: https://stackoverflow.com/questions/9784567/net-equivalent-of-curl-to-upload-a-file-to-rest-api, because `--upload-file` is the long option for `-T` – Luuk Jul 02 '20 at 13:30

1 Answers1

0

The solution was to simply pass the HttpRequest content as a byte array rather than as a memory stream.

internal static async Task<string> Post(string filePath)
{
    string fileName = new FileInfo(filePath).Name;

    //Load the file contents into a byte array using the System.IO.File.ReadAllBytes() method.
    byte[] fileBytes = File.ReadAllBytes(filePath);

    using (var httpClient = new HttpClient())
    {
        httpClient.BaseAddress = new Uri(Context.RESTUrl);
        httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(@"Basic", Context.EncodedAuthHeader);
        HttpRequestMessage httpRequest = new HttpRequestMessage(HttpMethod.Post, Context.RESTUrl);

        //Pass the file bytes as a ByteArrayContent object
        httpRequest.Content = new ByteArrayContent(fileBytes);

        httpRequest.Content.Headers.ContentType = new MediaTypeHeaderValue(Constants.ContentType);
        httpRequest.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue(@"form-data")
        {
            Name = "fileUpload",
            FileName = fileName
        };

        var response = httpClient.SendAsync(httpRequest).Result;
        validResponse = response.StatusCode == HttpStatusCode.Created;

        var contents = await response.Content.ReadAsStringAsync();
        return contents;
    }
}
Mike Bruno
  • 600
  • 2
  • 9
  • 26