Search code examples
c#uwprangehttpclientput

HttpClient putAsync request with Content-Length and Range in C#


Need to develop C# HttpClient PUT request for uploading image. Here is the curl request working well.

curl --location --request PUT 'https://somewheretest.com/abcd/efgh' \
--header 'Content-Type: application/octet-stream' \
--header 'Range: bytes=0-99999' \
--header 'Content-Length: 100000' \
--data-binary '@D:\image.jpg'

I've tried with HttpClient sending request PutAsync with MultipartFormDataContent, gets response Invalid Range. Any suggestion appreciated for the valid way to request uploading image to the server in C# UWP.

I've followed sort of ways. But only CURL is working perfectly. All other's code replies Invalid Range.

1st#

public static async Task<bool> fileUpload(string filePath, long fileSize)
{
    string url = "";

    try
    {
        string range = "bytes=0-" + (fileSize - 1).ToString();

        using (var client = new System.Net.Http.HttpClient())
        {
            //client.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36");
            //client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/octet-stream");
            //client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Length", fileSize.ToString());
            //client.DefaultRequestHeaders.TryAddWithoutValidation("Range", range);
            
            Uri uri = new Uri(url);

            using (var content = new MultipartFormDataContent())
            {
                FileStream fs = File.OpenRead(filePath);
                var streamContent = new StreamContent(fs);

                //HttpContent contents = new StringContent(filePath);
                //streamContent.Headers.TryAddWithoutValidation("Content-Type", "application/octet-stream");
                //streamContent.Headers.TryAddWithoutValidation("Content-Length", fileSize.ToString());
                //streamContent.Headers.TryAddWithoutValidation("Range", range);

                //content.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data");

                content.Add(new StringContent("Content-Type"), "application/octet-stream");
                content.Add(new StringContent("Range"), range);
                content.Add(new StringContent("Content-Length"), fileSize.ToString());
                content.Add(streamContent, "file", Path.GetFileName(filePath));

                using (var message = await client.PutAsync(uri, content))
                {
                    var input = await message.Content.ReadAsStringAsync();
                    //var result = JsonSerializer.Deserialize<FileUploadResult>(input);
                    Debug.WriteLine($"Response File Upload: {input}");

                    return true;
                }
            }
        }
    }
    catch (Exception ex)
    {
        Debug.WriteLine(ex.ToString());
        return false;
    }
}

2nd#

public static async Task<bool> UploadMultipart(byte[] file, string filename, string url)
{
    string contentType = "application/octet-stream";
    var webClient = new WebClient();
    string boundary = "------------------------" + DateTime.Now.Ticks.ToString("x");
    webClient.Headers.Add("Content-Type", "multipart/form-data; boundary=" + boundary);
    var fileData = webClient.Encoding.GetString(file);
    var package = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"file\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n{3}\r\n--{0}--\r\n", boundary, filename, contentType, fileData);

    var nfile = webClient.Encoding.GetBytes(package);

    byte[] resp = webClient.UploadData(url, "PUT", nfile);

    return true;
}

3rd#

public static async Task<bool> fileUpload(ValueSet issueToken, string filePath, byte[] fileInByte)
{
    int fileSize = fileInByte.Length;
    //string range = "bytes=0-" + (fileSize - 1).ToString();
    string url = "";

    var httpClient = new System.Net.Http.HttpClient();

    try
    {
        //StreamContent streamContent = new StreamContent(new FileStream(filePath, FileMode.Open, FileAccess.Read));
        StreamContent streamContent = new StreamContent(new MemoryStream(fileInByte));
        streamContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");
        streamContent.Headers.ContentRange = new System.Net.Http.Headers.ContentRangeHeaderValue(0, fileSize - 1);
        streamContent.Headers.ContentLength = fileSize;

        using (var message = await httpClient.PutAsync(url, streamContent))
        {
            var input = await message.Content.ReadAsStringAsync();
            //var result = JsonSerializer.Deserialize<FileUploadResult>(input);
            Debug.WriteLine($"Response File Upload: {input}");

            return true;
        }
    }
    catch(Exception ex)
    {
        Debug.WriteLine(ex);
        return false;
    }
}

Solution

  • The only reason for not working, System.Net.Http.HttpClient behaves differently in UWP which I got from wireshark. And another reason server has very old configuration which does not support multipart in the request. Anyway here is my solution with Windows.Web.Http.HttpClient.

    public static async Task<bool> fileUpload(ValueSet issueToken, string filePath, byte[] fileInByte)
    {
        int fileSize = fileInByte.Length;
        string range = "bytes=0-" + (fileSize - 1).ToString();
        string url = "https://somewheretest.com/abcd/efgh";
    
        var httpClient = new Windows.Web.Http.HttpClient();
        httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Range", range);
        
        try
        {
            HttpStreamContent streamContent = new HttpStreamContent(new FileStream(filePath, FileMode.Open, FileAccess.Read));
            streamContent.Headers.ContentType = new HttpMediaTypeHeaderValue("application/octet-stream");
            
            using (var message = await httpClient.PutAsync(new Uri(url), streamContent))
            {
                var output = await message.Content.ToString();
                Debug.WriteLine($"Response File Upload: {output}");
    
                return true;
            }
        }
        catch(Exception ex)
        {
            Debug.WriteLine(ex);
            return false;
        }
    }