Skip to content

Can no longer add JSON manually to a request as a parameter #1816

Closed

Description

@kendallb

Describe the bug
In RestSharp v106 and earlier, it was possible to add JSON to the request using the following sequence:

request.AddParameter("application/json", myJsonString, ParameterType.RequestBody);

With RestSharp v107 this no longer works. Instead you get a request like this:

POST /soa-infra/resources/GWS/ProductAvailability/Availability HTTP/1.1
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)
Accept: application/xml, text/xml, application/json, text/json, text/x-json, text/javascript
Content-Type: application/json; boundary="030269ab-0029-48b8-b40e-d12d4445826e"
Content-Length: 197
Host: ws.specialized.com
Cache-Control: no-cache
Connection: keep-alive
--030269ab-0029-48b8-b40e-d12d4445826e
Content-Type: text/plain; charset=utf-8
Content-Disposition: form-data; name="application/json"
System.Byte[]
--030269ab-0029-48b8-b40e-d12d4445826e--

when it should be like this:

POST /soa-infra/resources/GWS/ProductAvailability/Availability HTTP/1.1
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)
Accept: application/xml, text/xml, application/json, text/json, text/x-json, text/javascript
Content-Type: application/json
Content-Length: 232
Host: ws.specialized.com
Cache-Control: no-cache
Connection: keep-alive
{"CredentialRequest":{"Username":"XXXX", ... [rest of JSON snipped]

To Reproduce
Try to add JSON manually to the body of the request as above.

Expected behavior
It should behave the same as is you had called the following, which is how v107 expects you to do it:

request.AddBody(myJsonString, "application/json");

While you could argue that might be the 'correct' way, the problem is the old libraries fully supported adding the request body that way and the API still appears to support it as it has the correct function signature for it. Anyone porting existing code will run into this so it should be fixed.

Desktop (please complete the following information):

  • Windows 10, Windows Server 2016
  • .NET Framework
  • Version 4.8

Activity

  1. kendallb commented on Mar 29, 2022

    @kendallb
    ContributorAuthor

    Ok fixed in this PR with unit test that fails without the fix, and passes with it:

    #1817

    The problem is this line:

    ParameterType.RequestBody => new BodyParameter(name, value!, Serializers.ContentType.Plain),

    That is not correct as body parameters have no 'name'. If you look at the implementation of how it is done in the Request.AddBody function, it needs to use the name as the content type which is how it was supported previously in v106:

    DataFormat.Binary => request.AddParameter(new BodyParameter("", obj, contentType ?? ContentType.Binary)),
  2. jochenwezel commented on Apr 13, 2022

    @jochenwezel

    Might be the same issue or slightly different:

    Required request data (works before v107)

    POST https://xxx/documents HTTP/1.1
    Authorization: Bearer xxxxx
    Accept: application/json, text/json, text/x-json
    Content-Type: multipart/form-data; boundary=---------2F81A6B2-EF97-4751-8E1A-3E1AD1F81324
    Host: xxxxx
    Content-Length: 16091
    Accept-Encoding: gzip, deflate
    
    -----------2F81A6B2-EF97-4751-8E1A-3E1AD1F81324
    Content-Type: application/json
    Content-Disposition: form-data; name="metadata"
    
    {
      "some json"
    }
    -----------2F81A6B2-EF97-4751-8E1A-3E1AD1F81324
    Content-Disposition: form-data; name="document"; filename="TestFile.txt"
    Content-Type: application/octet-stream
    
    ...
    

    Current result of Content-Type "text/plain" with v107 which doesn't work

    POST https://xxx/documents HTTP/1.1
    Authorization: Bearer xxxxx
    Accept: application/json, text/json, text/x-json, text/javascript
    Content-Type: multipart/form-data; boundary="7afa5cc6-fd32-46c5-b2b5-3981faa9960b"
    Host: xxxxx
    Content-Length: 16071
    Expect: 100-continue
    Accept-Encoding: gzip
    
    --7afa5cc6-fd32-46c5-b2b5-3981faa9960b
    Content-Type: text/plain; charset=utf-8
    Content-Disposition: form-data; name=metadata
    
    {
      "some json"
    }
    --7afa5cc6-fd32-46c5-b2b5-3981faa9960b
    Content-Disposition: form-data; name="document"; filename="TestFile.txt"
    Content-Type: application/octet-stream
    ...
    
    

    Current code triage: required overloads are missing in RestSharp API

                //Request initialization
                RestRequest uploadRequest = CreateRestRequest(URI_RESOURCE, Method.Post, "multipart/form-data");
                uploadRequest.AlwaysMultipartFormData = true;
    
                //doesn't work: CreateParameter always assigns ContentType = "text/plain" for ParameterType.RequestBody
                uploadRequest.AddParameter(JsonParameter.CreateParameter("metadata", @"{ \"some json\" }", ParameterType.RequestBody));
    
                //doesn't work: overwrite initialized ContentType not possible (read-only property)
                var metaParam = (BodyParameter)JsonParameter.CreateParameter("metadata", @"{ \"some json\" }", ParameterType.RequestBody);
                metaParam.ContentType = "text/json";
    
                //doesn't work: AddJsonBody always adds body as JSON, but attachment name "metadata" can't be defined + not desired change by implementation code with line: request.RequestFormat = DataFormat.Json;
                uploadRequest.AddJsonBody<string>(@"{ \"some json\" }")
    
                //doesn't work: JsonParameter constructor doesn't provide ParameterType argument, after construction property is again read-only
                uploadRequest.AddParameter(new JsonParameter("metadata" @"{ \"some json\" }", "application/json") { Type = ParameterType.RequestBody });
    
                //remaining steps work again, just for informational purposes here...
                //add 2nd body attachment with raw file data
                uploadRequest.AddFile(fileName, filePath);

    Proposal patch in class "Parameter": Added method CreateBodyParameter (besides method CreateParameter)

            public static Parameter CreateBodyParameter(string? name, object? value, string contentType)
            {
                        return new BodyParameter(name, value, contentType ?? "text/plain");
            }

    Found workaround in my solution

                //Request initialization
                RestRequest uploadRequest = CreateRestRequest(URI_RESOURCE, Method.Post, "multipart/form-data");
                uploadRequest.AlwaysMultipartFormData = true;
    
                //WORKAROUND: create BodyParameter instance manually
                uploadRequest.AddParameter(new BodyParameter("metadata" @"{ \"some json\" }", "application/json"));
    
                //remaining steps work again, just for informational purposes here...
                //add 2nd body attachment with raw file data
                uploadRequest.AddFile(fileName, filePath);
  3. kendallb commented on Apr 13, 2022

    @kendallb
    ContributorAuthor

    Looks like a similar issue, yes.

  4. alexeyzimarev commented on Apr 14, 2022

    @alexeyzimarev
    Member

    Adding a body parameter with name = content type

    I agree that it might be a good idea to make the legacy-compatible call like the one below, to work.

    request.AddParameter("application/json", myJsonString, ParameterType.RequestBody);

    However, I am very unhappy about this API, because it is very implicit. The parameter name argument is the name of the parameter. It's not for the content type. The implicit way of the old API is confusing. It should've never worked as it did. So, if we'd t make it work again, it needs to have a visible warning that you should not be doing it.

    Using AddJsonBody

    I am sorry guys but this warning is there for a reason, and I keep responding to SO questions, and I keep seeing issues opened. AddJsonBody is for objects to be serialized.

    image

    https://restsharp.dev/usage.html#request-body

    I really would appreciate people reading the docs before claiming "it doesn't work".

  5. jochenwezel commented on Apr 14, 2022

    @jochenwezel

    Using AddJsonBody

    I am sorry guys but this warning is there for a reason, and I keep responding to SO questions, and I keep seeing issues opened. AddJsonBody is for objects to be serialized.

    image

    https://restsharp.dev/usage.html#request-body

    I really would appreciate people reading the docs before claiming "it doesn't work".

    You referenced AddStringBody(this RestRequest request, string body, string contentType), but this method doesn't allow to define a name for the body. That's why it's not working for my project.

  6. 1 remaining item

  7. kendallb commented on Apr 14, 2022

    @kendallb
    ContributorAuthor

    Yes the old behaviour is a nasty side effect. It's not clear if that was always intentional, or something that worked and everybody just did it.

  8. stale commented on Jun 23, 2022

    @stale

    This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

  9. repo-ranger commented on Jun 23, 2022

    @repo-ranger

    ⚠️ This issue has been marked wontfix and will be closed in 3 days

  10. jochenwezel commented on Jun 23, 2022

    @jochenwezel

    @kendallb already prepared several commits - this ticket should keep open until they're accepted, isn't it?

  11. alexeyzimarev commented on Jun 23, 2022

    @alexeyzimarev
    Member

    Yeah, I keep reopening it. Not ready to turn off the bot yet.

  12. stale commented on Aug 13, 2022

    @stale

    This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

  13. repo-ranger commented on Aug 13, 2022

    @repo-ranger

    ⚠️ This issue has been marked wontfix and will be closed in 3 days

  14. david-siegert commented on Feb 21, 2023

    @david-siegert

    I think I have an issue connected to this one. When I need to do the same type of request as @jochenwezel. I need a multipart/form-data. Send a file and json. But the consuming API is strict and needs the body parameter Content-Type be equal to exactly "application/json".

    BodyParameter a = new BodyParameter("\"itemDetail\"", createItemRequest.Serialize(), "application/json", DataFormat.None)
    request.AddParameter(a);
    request.AddFile(imageRequest.FieldId, imageRequest.Image, imageRequest.FileName, "application/octet-stream");

    and on the client I have set:

    client.Options.DisableCharset = true,

    This produces:

    --64d660c6-0047-44eb-bb2f-c9a591f8fe01
    Content-Type: application/json; charset=utf-8
    Content-Disposition: form-data; name="itemDetail"
    
    {"sections":[{"link":"/api/v3/w..... json truncated
    --64d660c6-0047-44eb-bb2f-c9a591f8fe01--
    

    When expected Content-Type is:
    Content-Type: application/json

  15. alexeyzimarev commented on Feb 21, 2023

    @alexeyzimarev
    Member

    You mean that the charset is breaking it? I haven't implementing DisableCharset for multipart forms, not even sure if it can be done.

  16. david-siegert commented on Feb 21, 2023

    @david-siegert

    No, something else changes content type from Content-Type: application/json to Content-Type: application/json; charset=utf-8 . When I use multipart/form-data. I expected DisableCharset to solve it. But now I understand that is not implemented. Is there some workaround?

  17. alexeyzimarev commented on Feb 22, 2023

    @alexeyzimarev
    Member

    Well, it's not something else, it's the .NET form data content class :) I need to check if it's possible to change its behaviour.

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