question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Cannot Send GET Request with Content-Type Header with RestSharp v107

See original GitHub issue

After upgrading to v107, I started getting the following error when trying to execute a GET request with the Content-Type: application/force-download header: Cannot send a content-body with this verb-type.

The header is the only parameter in the request, but it seems like RestSharp transparently adds a body causing the error.

All attempts below causes the error mentioned when executing the request: restRequest.AddHeader("Content-Type", "application/force-download"); restRequest.Parameters.AddParameter(new BodyParameter("", "", "application/force-download", DataFormat.None)); restRequest.AddStringBody("", "application/force-download");

While it may not be a good practice to use this header parameter with a GET request, it is unfortunately required for me to perform some operation with a system from a vendor and the last version of RestSharp does not support this anymore.

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:18 (12 by maintainers)

github_iconTop GitHub Comments

1reaction
alexeyzimarevcommented, Feb 4, 2022

@VictorRH have you read the docs following the link I posted? RestSharp adds the necessary headers automatically if the request has a body.

Here’s the code that would work:

var options = new RestClientOptions("https://enqvvdg27q3o.x.pipedream.net/") {
    UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36"
};
var payload = "key=value&foo=bar";
var client = new RestClient(options);
var request = new RestRequest("", Method.Post)
    .AddHeader("Accept-Language", "en-US,en;q=0.9")
    .AddHeader("Origin", "urlorigin")
    .AddHeader("Referer", "urlReferer")
    .AddStringBody(payload, "application/x-www-form-urlencoded");

var response = await client.ExecutePostAsync(request);

and here is what the request looks like:

image

Notice that the content-type header is present, although if you use HttpTracer you won’t see it. It’s because HttpTracer does not print out content headers, it only shows you request headers.

1reaction
PierreCollardSuerocommented, Feb 3, 2022

I managed to apply a fix with a utility class using System.Net.HttpClient directly. The implementation might be too dirty for many, but the usage is very simple and clean:

// using System.Net.Http;
// using System.Net.Http.Headers;
// using System.Linq;
// using System.Threading;
// using System.Threading.Tasks;
// using System.Collections.Generic;
// using System.Reflection;
// using RestSharp;

public static class HttpMessageUtils
{
    public const string ContentTypeHeaderName = "Content-Type";

    class HandlerAllowingContentTypeHeaderOnGetRequests : DelegatingHandler
    {
        public HandlerAllowingContentTypeHeaderOnGetRequests(
            HttpMessageHandler p_innerHttpMessageHandler
        ) : base(p_innerHttpMessageHandler)
        { }

        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage p_request, CancellationToken p_cancellationToken)
        {
            FieldInfo invalidHeadersField =
                typeof(HttpHeaders).GetField("invalidHeaders", BindingFlags.NonPublic | BindingFlags.Instance) ??   // System.Net.Http v2.2+
                typeof(HttpHeaders).GetField("_invalidHeaders", BindingFlags.NonPublic | BindingFlags.Instance)     // System.Net.Http before v2.2
            ;

            HashSet<string> invalidHeaders = (HashSet<string>)invalidHeadersField.GetValue(p_request.Headers);

            if (invalidHeaders.Contains(ContentTypeHeaderName))
            {
                invalidHeaders.Remove(ContentTypeHeaderName);

                string contentTypeHeaderValue = p_request.Content.Headers.ContentType.MediaType;
                string requestContent = await p_request.Content.ReadAsStringAsync();

                if (string.IsNullOrWhiteSpace(requestContent))
                    p_request.Content = null;
                else
                    p_request.Content.Headers.Remove(ContentTypeHeaderName);

                p_request.Headers.Add(ContentTypeHeaderName, contentTypeHeaderValue);
            }

            HttpResponseMessage response = await base.SendAsync(p_request, p_cancellationToken);
            return response;
        }
    }

    public static HttpClient GetHttpClient(this RestClient p_restClient)
    {
        return ((TypeInfo)p_restClient.GetType())
            .DeclaredProperties
            .First(p => p.Name == "HttpClient")
            .GetValue(p_restClient)
            as HttpClient
        ;
    }

    private static FieldInfo GetHttpMessageHandlerField(this HttpClient p_httpClient)
    {
        return ((TypeInfo)p_httpClient.GetType().BaseType)
            .DeclaredFields
            .First(f => f.Name == "handler")
        ;
    }

    public static HttpMessageHandler GetMessageHandler(this HttpClient p_httpClient)
    {
        return p_httpClient.GetHttpMessageHandlerField()
            .GetValue(p_httpClient)
            as HttpMessageHandler
        ;
    }

    public static void SetMessageHandler(this HttpClient p_httpClient, HttpMessageHandler p_newHttpMessageHandler)
    {
        p_httpClient.GetHttpMessageHandlerField().SetValue(p_httpClient, p_newHttpMessageHandler);
    }

    public static HttpMessageHandler GetInnerMessageHandler(this RestClient p_restClient)
    {
        return p_restClient.GetHttpClient().GetMessageHandler();
    }

    public static void AllowContentTypeHeaderOnGetRequests(this RestClient p_restClient)
    {
        HttpMessageHandler innerMessageHandler = p_restClient.GetInnerMessageHandler();
        HttpMessageHandler newMessageHandler = new HandlerAllowingContentTypeHeaderOnGetRequests(innerMessageHandler);
        p_restClient.GetHttpClient().SetMessageHandler(newMessageHandler);
    }
}
RestClientOptions restClientOptions = new(p_baseURL) { Credentials = p_credentials };
RestClient restClient = new(restClientOptions);
RestRequest restRequest = new(p_relativeResourcePath, p_method);

restRequest.AddHeader("Content-Type", "application/force-download");
restClient.AllowContentTypeHeaderOnGetRequests();
RestResponse restResponse = await restClient.ExecuteAsync(restRequest, p_method);
Read more comments on GitHub >

github_iconTop Results From Across the Web

RestSharp: Adding content-type
Try with: request.AddParameter("Content-Type", "application/x-www-form-urlencoded", ParameterType.HttpHeader);.
Read more >
RestSharp Next (v107+)
RestSharp got a major upgrade in v107, which contains quite a few breaking ... The Content-Type header is the content header, not the...
Read more >
v107.3 issue with Method.Get
Net.ProtocolViolationException: Cannot send a content-body with this verb-type. at RestSharp.RestClient.ThrowIfError(RestResponse response) at RestSharp.
Read more >
RestSharp In .NET 6.0
In this article, ee learn how to call RestSharp v107 in .Net6.0.
Read more >
RESTful API testing in C# with RestSharp
So far, we've only written assertions on the HTTP status code and the content type header value for the response. But what if...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found