Skip to content

Post with file parameter order #2115

Closed
Closed

Description

@kyugoa

DO NOT USE ISSUES FOR QUESTIONS

Describe the bug
when posting to an endpoint with File attachment, if there are other input parameters in the body, the File parameter is always render first regardless of the order the parameter is added.

To Reproduce
call an api endpoint with file attachment and additional parameter like fileName and fileType.

` using var fileServiceClient = GetFileServiceClient();
var request = new RestRequest("file/v1/files", Method.Post);

  //added these parameters first
  request.AddJsonBody(new FileUploadRequestModel { Type = "tps-volume-titles", FileName = fileName });

  //then the file parameter
  request.AddFile("file", fileContent, fileName, "text/csv");
  request.AlwaysMultipartFormData = true;

  var response = await fileServiceClient.PostAsync(request).ConfigureAwait(false);

  if (!response.IsSuccessStatusCode)
  {
    _logger.LogError($"Failed to upload file {fileName}");
  }

`

Expected behavior
Expected the http request to be:

POST https://somedomain.com/file/v1/files HTTP/1.1
Host: file-service.adsp-uat.alberta.ca
Authorization: Bearer eyxxx
Accept: application/json, text/json, text/x-json, text/javascript, application/xml, text/xml
User-Agent: RestSharp/110.2.0.0
Accept-Encoding: gzip, deflate, br
Content-Type: multipart/form-data; boundary="0a1f4db8-6981-4592-aff5-7b12b4e00197"
Content-Length: 115113

--0a1f4db8-6981-4592-aff5-7b12b4e00197
Content-Type: text/plain; charset=utf-8
Content-Disposition: form-data; name=type

tps-volume-titles
--0a1f4db8-6981-4592-aff5-7b12b4e00197
Content-Type: text/plain; charset=utf-8
Content-Disposition: form-data; name=filename

1680672668.csv
--0a1f4db8-6981-4592-aff5-7b12b4e00197
Content-Type: text/csv
Content-Disposition: form-data; name="file"; filename="1680672668.csv"

"xxx","2023-07-13 09:28:48",,ON00001,,"242006882001","S","*",,"2023-07-11","Subdivision Plan",,,"N",,"T","Fee Simple","242 006 882 +2",,,"2023-07-11"

--0a1f4db8-6981-4592-aff5-7b12b4e00197--

Actual rendered http request

POST https://somedomain.com/file/v1/files HTTP/1.1
Host: file-service.adsp-uat.alberta.ca
Authorization: Bearer eyxxx
Accept: application/json, text/json, text/x-json, text/javascript, application/xml, text/xml
User-Agent: RestSharp/110.2.0.0
Accept-Encoding: gzip, deflate, br
Content-Type: multipart/form-data; boundary="0a1f4db8-6981-4592-aff5-7b12b4e00197"
Content-Length: 115113

--0a1f4db8-6981-4592-aff5-7b12b4e00197
Content-Type: text/csv
Content-Disposition: form-data; name="file"; filename="1680672668.csv"

"xxx","2023-07-13 09:28:48",,ON00001,,"242006882001","S","*",,"2023-07-11","Subdivision Plan",,,"N",,"T","Fee Simple","242 006 882 +2",,,"2023-07-11"

--0a1f4db8-6981-4592-aff5-7b12b4e00197
Content-Type: text/plain; charset=utf-8
Content-Disposition: form-data; name=type

tps-volume-titles
--0a1f4db8-6981-4592-aff5-7b12b4e00197
Content-Type: text/plain; charset=utf-8
Content-Disposition: form-data; name=filename

1680672668.csv
--0a1f4db8-6981-4592-aff5-7b12b4e00197--

Stack trace

Desktop (please complete the following information):

  • OS: windows
  • .NET version 6
  • Version 110.2.0

Additional context
Add any other context about the problem here.

Activity

  1. b166er commented on Jul 14, 2023

    @b166er

    I have the same problem!

    my first code, was very simple and naive. unfortunately it did not work as i expected:

    // Create RestClient
    RestClient client = new RestClient("https://api-server");
    
    // Create RestRequest
    RestRequest request = new RestRequest("path", Method.POST) {FormBoundary = "MySpecialBounderyIdentifierTest123"};
    
    request.AddJsonBody(myJsonData);
    request.AddFile(filename, fileContent, filename);
    
    // overwrite Content-Type with my custom requirement
    request.AddOrUpdateHeader("Content-Type", "multipart/mixed");
    
    // Execute the request
    IRestResponse response = client.Execute(request);
    
    // Handle the response
    if (response.IsSuccessful)
    {
        Console.WriteLine("File uploaded successfully!");
    }
    else
    {
        Console.WriteLine("File upload failed. Error: " + response.ErrorMessage);
    } 

    output with Version 110.2.0 is:

    Authorization: Basic myloginauthkey
    Accept: application/json, text/json, text/x-json, text/javascript, application/xml, text/xml
    User-Agent: RestSharp/110.2.0.0
    Content-Type: multipart/mixed; 
    boundary="MySpecialBounderyIdentifierTest123"
    Host: api-server
    Content-Length: 123
    Connection: Keep-Alive
    
    --MySpecialBounderyIdentifierTest123
    Content-Type: application/zip
    Content-Disposition: form-data; name="mytest.zip"; filename="mytest.zip"
    ...binary-bytes...
    --MySpecialBounderyIdentifierTest123
    Content-Type: application/json; charset=utf-8
    Content-Disposition: form-data; name="application/json"
    {"meta": [{"title": "My Homework","author": {"name": "Tessa","adress": null},"created": 1550743894373}]}
    --MySpecialBounderyIdentifierTest123--
    

    my expected output was:

    Authorization: Basic myloginauthkey
    Accept: application/json, text/json, text/x-json, text/javascript, application/xml, text/xml
    User-Agent: RestSharp/110.2.0.0
    Content-Type: multipart/mixed; boundary="MySpecialBounderyIdentifierTest123"
    Host: api-server
    Content-Length: 123
    Connection: Keep-Alive
    
    --MySpecialBounderyIdentifierTest123
    Content-Type: application/json; charset=utf-8
    Content-Disposition: form-data; name="application/json"
    {"meta": [{"title": "My Homework","author": {"name": "Tessa","adress": null},"created": 1550743894373}]}
    --MySpecialBounderyIdentifierTest123
    Content-Type: application/zip
    Content-Disposition: form-data; name="mytest.zip"; filename="mytest.zip"
    ...binary-bytes...
    --MySpecialBounderyIdentifierTest123--
    

    Here is my ugly code to set the order manually. It would be so great if the output of the parameters were in the same order as the executing Add-Methods, or at least some simple functionality to set the order, e.g. an order parameter.

    using System.Text;
    using System.Linq;
    
    class Program
    {
        static void Main(string[] args)
        {
            // Create RestClient
            RestClient client = new RestClient("https://api-server");
            
            // Create RestRequest
            RestRequest request = new RestRequest("path", Method.POST);
            
            string boundary = "MySpecialBounderyIdentifierTest123";
            string filename = "mytest.zip";
            
            // set manually content and encode all data to bytes
            byte[] start = Encoding.UTF8.GetBytes($"--{boundary}{Environment.NewLine}");
            byte[] separator = Encoding.UTF8.GetBytes($"{Environment.NewLine}{boundary}--{Environment.NewLine}");
            byte[] end = Encoding.UTF8.GetBytes($"{Environment.NewLine}--{boundary}--{Environment.NewLine}");
            
            string json = @"{
                ""meta"": [{
                        ""title"": ""My Homework"",
                        ""author"": 
                        {
                            ""name"": ""Tessa"",
                            ""adress"": null
                        }, 
                        ""created"": 1550743894373
                    }]
            }";
            // Content-Disposition is optional and not necessary for me/the api-server
            byte[] jsonMeta = Encoding.UTF8.GetBytes($"Content-Type: application/json{Environment.NewLine}{Environment.NewLine}{json}");
            byte[] fileMeta = Encoding.UTF8.GetBytes($"Content-Type: application/zip{Environment.NewLine}Content-Disposition: form-data; name=\"file\"; filename=\"{filename}\"{Environment.NewLine}{Environment.NewLine}");
            
            // use Linqs byte-concatenation
            IEnumerable<byte> requestBytes;
            
            // Combine first json data, then file content! the order is very important.
            requestBytes = start // start with boundary-start-sequence
                .Concat(jsonMeta) // important: json Data MUST be in the first position, before binary file payload
                .Concat(separator) // add boundary separator
                .Concat(fileMeta) // file data need as second parameter, after json data!
                .Concat(File.ReadAllBytes(filename)) // add file binary payload data as bytes
                .Concat(end) // add boundary-endsequence
            ;
            
            // in my personal case, I have to set an additional custom Content-Type Header
            // multipart/form-data does not work with my particular api-server!
            string header = $"multipart/mixin; boundary={boundary}";
    
            // set manually header and byte-content to parameter
            request.AddParameter(header, requestBytes.toArray(), ParameterType.RequestBody);
            
            // Execute the request
            IRestResponse response = client.Execute(request);
            
            // Handle the response
            if (response.IsSuccessful)
            {
                Console.WriteLine("File uploaded successfully!");
            }
            else
            {
                Console.WriteLine("File upload failed. Error: " + response.ErrorMessage);
            }       
        }
    }
  2. koo9 commented on Jul 14, 2023

    @koo9

    just render the paramter by the order added would be sufficient. I believe you can set the file content type in the .AddFile() method but the overall content-type is still multipart/form-data

  3. changed the title [-]Post with file parameter order bug[/-] [+]Post with file parameter orde[/+] on Jul 15, 2023
  4. changed the title [-]Post with file parameter orde[/-] [+]Post with file parameter order[/+] on Jul 15, 2023
  5. alexeyzimarev commented on Jul 15, 2023

    @alexeyzimarev
    Member

    Body parameters are added to the request message in the same order as they are added to RestRequest. But, files are added separately, as well as POST parameters when the content is a multipart form.

  6. alexeyzimarev commented on Jul 15, 2023

    @alexeyzimarev
    Member

    Duplicate of #2098

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions