0

When posting data with Flurl's PostUrlEncodedAsync, the following Content-Type is automatically set:

application/x-www-form-urlencoded; charset=utf-8

How do I remove the charset=utf-8 part?

I already tried:

flurlClient.ConfigureHttpClient(c => c.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/x-www-form-urlencoded"));

but it doesnt work. Suggestion comes from: https://stackoverflow.com/a/44548514/915414

Kenci
  • 4,794
  • 15
  • 64
  • 108

2 Answers2

0

Instead of using Flurl, I tried to achieve the same goal with HttpClient. That didnt work, so I created an extension method for Flurl instead.

https://stackoverflow.com/a/44543016/915414 suggests using StringContent to change the Content-Type:

var jobInJson = JsonConvert.SerializeObject(job);
var json = new StringContent(jobInJson, Encoding.UTF8);
json.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json; odata=verbose");

var flurClient = GetBaseUrlForOperations("Jobs");

return await flurClient.PostAsync(json).ReceiveJson<Job>();

Although this does change the Content-Type, the charset=utf-8 still remains.

I decompiled System.Net.Http.StringContent to see how it works. It defaults to a charset:

this.Headers.ContentType = new MediaTypeHeaderValue(mediaType == null ? "text/plain" : mediaType)
{
     CharSet = encoding == null ? HttpContent.DefaultStringEncoding.WebName : encoding.WebName
};

And guess what... At its core, PostUrlEncodedAsync uses StringContent.

So, I created an extension method for Flurl, that uses a similar implementation of StringContent, where CharSet = "";

PostUrlEncodedAsyncWithoutCharset:

public static class HttpExtensions
{
    public static Task<HttpResponseMessage> PostUrlEncodedAsyncWithoutCharset(this IFlurlClient client, object data, CancellationToken cancellationToken = default(CancellationToken), HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead)
    {
        CapturedUrlContentCustom urlEncodedContent = new CapturedUrlContentCustom(client.Settings.UrlEncodedSerializer.Serialize(data));
        return client.SendAsync(HttpMethod.Post, (HttpContent)urlEncodedContent, new CancellationToken?(cancellationToken), completionOption);
    }
}

CapturedUrlContentCustom:

public class CapturedUrlContentCustom : CapturedStringContentCustom
{
    public CapturedUrlContentCustom(string data)
    : base(data, (Encoding) null, "application/x-www-form-urlencoded")
    {
    }
}

CapturedStringContentCustom:

public class CapturedStringContentCustom : CustomStringContent
{
    public string Content { get; }
    public CapturedStringContentCustom(string content, Encoding encoding = null, string mediaType = null)
        : base(content, encoding, mediaType)
    {
        this.Content = content;
    }
}

CustomStringContent:

public class CustomStringContent : ByteArrayContent
    {
        private const string defaultMediaType = "application/x-www-form-urlencoded";


        public CustomStringContent(string content)
      : this(content, (Encoding)null, (string)null)
        {
        }


        public CustomStringContent(string content, Encoding encoding)
      : this(content, encoding, (string)null)
        {
        }


        public CustomStringContent(string content, Encoding encoding, string mediaType)
      : base(CustomStringContent.GetContentByteArray(content, encoding))
        {
            this.Headers.ContentType = new MediaTypeHeaderValue(mediaType == null ? "application/x-www-form-urlencoded" : mediaType)
            {
                CharSet = ""
            };
        }

        private static byte[] GetContentByteArray(string content, Encoding encoding)
        {
            if (content == null)
                throw new ArgumentNullException(nameof(content));
            if (encoding == null)
                encoding = Encoding.UTF8;
            return encoding.GetBytes(content);
        }
    }

Now, you can call PostUrlEncodedAsyncWithoutCharset and charset=utf-8 will not appear.

Kenci
  • 4,794
  • 15
  • 64
  • 108
0

It's possible with Dio — https://pub.dev/packages/dio

Result looks like:

final dio = Dio();

final response = await dio.post(
  'https://some.place.com/foo/bar',
  data: jsonEncode(<String, String>{
    'name': 'Flutter',
  }),
  options: Options(
    headers: {},
    contentType: 'application/json',
  ),
);

log(jsonEncode(response.data));
Anton Starcev
  • 1,138
  • 12
  • 9