Skip to content

AddJsonBody() ignores contentType argument #1645

Closed

Description

@AJIOB

Expected Behavior

IRestRequest.AddJsonBody(obj, contentType) will send correct ContentType field value

Actual Behavior

IRestRequest.AddJsonBody(obj, contentType) force sends application/json ContentType field

Steps to Reproduce the Problem

  1. Enable Wireshark
  2. Send some object with custom contentType (for example, hello/world)
  3. See sent packet with default HTTP header: ContentType: application/json (should be ContentType: hello/world)

Specifications

  • Version: 106.13.0
  • Platform: Windows 10 x64 Pro
  • Subsystem: Windows

Activity

  1. AJIOB commented on Nov 2, 2021

    @AJIOB
    Author

    Looks like the library uses ISerializer.ContentType field instead of IRestSerializer.SupportedContentTypes:
    https://github.com/restsharp/RestSharp/blob/dev/src/RestSharp/RestRequestExtensions.cs#L41

  2. alexeyzimarev commented on Nov 7, 2021

    @alexeyzimarev
    Member

    It's quite inconsistent that we allow specifying the content type for AddJsonBody. Normally, you'd need a custom serialiser if you want to change its content type.

  3. AJIOB commented on Nov 7, 2021

    @AJIOB
    Author

    @alexeyzimarev Why is it inconsistent to specify custom contentType, that is supported by default serializer?

    I really need to use application/my_custom_type+json, sorry for inconsistent example.

    But nowadays I need to use an old version, where that works correctly (105.x).

  4. alexeyzimarev commented on Nov 7, 2021

    @alexeyzimarev
    Member

    What I mean is that taking the content type from the serialiser is correct, as the serialiser knows how to form the request correctly, and its content type. But I agree that life could be easier if all your server wants is a normal JSON but for some reason, it needs a custom content type (which is also JSON).

    The previous major version works correctly as it doesn't really support custom serialisers other than this weird way to add content handlers.

    In your case the execution path is different. If won't get into requestSerializer != null condition, so it will try finding the serialiser based on the data type. It will find the default JSON serialiser.

    Here is where you expect the custom content type to be assigned (last line):

    request.Body = new RequestBody(serializer.ContentType, serializer.ContentType, serializer.Serialize(body));
    

    The first argument should be body.ContentType ?? serializer.ContentType for your case to work.

    Please feel free to submit a PR. A test would be nice as well.

  5. alexeyzimarev commented on Dec 6, 2021

    @alexeyzimarev
    Member

    Looks like the library uses ISerializer.ContentType field instead of IRestSerializer.SupportedContentTypes

    The SupportedContentType property is used for deserialization only as we need to match deserializers with the response content type. So it's a list. The ContentType is what the serializer provides as the content type of the request.

  6. alexeyzimarev commented on Dec 6, 2021

    @alexeyzimarev
    Member

    I really need to use application/my_custom_type+json, sorry for inconsistent example.

    @AJIOB here's the scenario:

    • You have the default serializers for the client (XML and JSON) configured for the client
    • You add JSON payload to the body
    • We need to know how to serialize it, which we can't by looking at the custom content type

    The reason for it to work in v105 is that it was serializing immediately, but it stopped working when serializers were moved to the client. As you form the request without it to know about the client instance, the request has no access to client serializers. It's a trade-off to support more serializers easier by moving them to the client, and it solved loads of issues.

    Your particular issue is very easy to fix if you create your own serializer where the ContentType property has a value you need to be passed as the request content type. You literally can take any existing serializer code and replace the ContentType property value, then add it to the client.

    In terms of allowing to pass the content type when adding the JSON body to the request, it allows you to have more than one JSON serializer on the client, and choose one according to the content type provided. For example, you can have one default serializer and one custom serializer with your own content type.

    I am not exactly sure how to change the behaviour without breaking too much. It is possible to fix if the request would be created from the client, like client.CreateRequest, so the request will be aware of the client itself and its serializers. But it would be a major breaking change.

  7. AJIOB commented on Dec 6, 2021

    @AJIOB
    Author

    The SupportedContentType property is used for deserialization only as we need to match deserializers with the response content type. So it's a list. The ContentType is what the serializer provides as the content type of the request.

    Maybe we can use it as a possible variant for serializer too, can't we?

  8. AJIOB commented on Dec 6, 2021

    @AJIOB
    Author

    Your particular issue is very easy to fix if you create your own serializer where the ContentType property has a value you need to be passed as the request content type. You literally can take any existing serializer code and replace the ContentType property value, then add it to the client.

    @alexeyzimarev Yes, you are right. Thank you.

    IMHO, it looks like a crunch, not a stable solution.

  9. alexeyzimarev commented on Dec 8, 2021

    @alexeyzimarev
    Member

    If you compare it with HttpClient JSON extensions for System.Text.Json, you can see that they allow sending the content type. It's because their API is very explicit: PostJsonAsync, and you provide the payload right there. I am also not a big fan of how historically requests are made in RestSharp when you add the request body as a parameter. That way, the API tells you "add more than one body" and then it fails. I tried to make parameters more explicit, so I marked the Parameter constructor obsolete, but I got tons of complaints. I think RestSharp suffers from its legacy API design, and, unless it's fixed with lots of breaking changes (and more complaints), it will always be a compromise.

    As I was writing this, I got an idea, although it's another "hack". It's possible to select the serializer based on DataType, in addition to content type. So, if you only have one JSON serializer configured, it should be possible to find it and use your custom content type. However, it will be pretty much unclear which one to choose if you have more than one JSON serializer configured. I don't remember exactly if we allow more than one serializer for the same data type, I will check. Maybe it's still fixable/

  10. alexeyzimarev commented on Dec 8, 2021

    @alexeyzimarev
    Member

    @AJIOB try 106.15, it should work. Feel free to re-open the issue if it doesn't.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions