如何从HttpClient.PostAsJsonAsync()生成的Content-Type标头中删除charset = utf8?

oro*_*nbz 8 asp.net json httpclient utf-8 asp.net-web-api

我有HttpClient.PostAsJsonAsync()的问题

除了"Content-Type"标题中的"application/json"之外,该方法还添加了"charset = utf-8"

所以标题看起来像这样:

Content-Type:application/json; 字符集= utf-8的

虽然ASP.NET WebAPI对此标头没有任何问题,但我发现我作为客户端使用的其他WebAPI不接受带有此标头的请求,除非它只是application/json.

无论如何在使用PostAsJsonAsync()时从Content-Type中删除"charset = utf-8",还是应该使用其他方法?

解决方案: Yishai的积分!

using System.Net.Http.Headers;

public class NoCharSetJsonMediaTypeFormatter : JsonMediaTypeFormatter
{
   public override void SetDefaultContentHeaders(Type type, HttpContentHeaders headers, MediaTypeHeaderValue mediaType)
   {
       base.SetDefaultContentHeaders(type, headers, mediaType);
       headers.ContentType.CharSet = "";
   }
}

public static class HttpClientExtensions
{
    public static async Task<HttpResponseMessage> PostAsJsonWithNoCharSetAsync<T>(this HttpClient client, string requestUri, T value, CancellationToken cancellationToken)
    {
        return await client.PostAsync(requestUri, value, new NoCharSetJsonMediaTypeFormatter(), cancellationToken);
    }

    public static async Task<HttpResponseMessage> PostAsJsonWithNoCharSetAsync<T>(this HttpClient client, string requestUri, T value)
    {
        return await client.PostAsync(requestUri, value, new NoCharSetJsonMediaTypeFormatter());
    }
}
Run Code Online (Sandbox Code Playgroud)

Yis*_*zer 6

您可以从JsonMediaTypeFormatter派生并覆盖SetDefaultContentHeaders.

打电话base.SetDefaultContentHeaders()然后清除headers.ContentType.CharSet

然后根据以下代码编写自己的扩展方法:

public static Task<HttpResponseMessage> PostAsJsonAsync<T>(this HttpClient client, string requestUri, T value, CancellationToken cancellationToken)
{
    return client.PostAsync(requestUri, value, 
            new JsonMediaTypeFormatter(), cancellationToken);
}
Run Code Online (Sandbox Code Playgroud)

本质上是这样的:

public static Task<HttpResponseMessage> PostAsJsonWithNoCharSetAsync<T>(this HttpClient client, string requestUri, T value, CancellatioNToken cancellationToken)
{
    return client.PostAsync(requestUri, value, 
          new NoCharSetJsonMediaTypeFormatter(), cancellationToken);
}
Run Code Online (Sandbox Code Playgroud)


Dar*_*ler 5

为了更直接地控制您发送的有效负载,您可以创建派生的 HttpContent 类,而不是让您的对象传递给 ObjectContent 类,然后 ObjectContent 类将流委托给 Formatter 类。

一个同时支持读写的 JsonContent 类看起来像这样,

public class JsonContent : HttpContent
{
    private readonly Stream _inboundStream;
    private readonly JToken _value;

    public JsonContent(JToken value)
    {
        _value = value;
        Headers.ContentType = new MediaTypeHeaderValue("application/json");
    }

    public JsonContent(Stream inboundStream)
    {
        _inboundStream = inboundStream;
    }

    public async Task<JToken> ReadAsJTokenAsync()
    {
        return _value ?? JToken.Parse(await ReadAsStringAsync());
    }

    protected async override Task<Stream> CreateContentReadStreamAsync()
    {
        return _inboundStream;
    }

    protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
    {
        if (_value != null)
        {
            var jw = new JsonTextWriter(new StreamWriter(stream)) {Formatting = Formatting.Indented};
            _value.WriteTo(jw);
            jw.Flush();
        } else if (_inboundStream != null)
        {
            return _inboundStream.CopyToAsync(stream);
        }
        return Task.FromResult<object>(null);
    }

    protected override bool TryComputeLength(out long length)
    {
        length = -1;
        return false;
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            _inboundStream.Dispose();   
        }
        base.Dispose(disposing);
    }
}
Run Code Online (Sandbox Code Playgroud)

一旦你有了这门课,你就可以做,

var content = new JsonContent(myObject);
_httpClient.PostAsync(uri,content);
Run Code Online (Sandbox Code Playgroud)

如果您需要更改任何内容标题,您可以在发送请求之前手动执行此操作。如果您需要弄乱任何请求标头,那么您可以使用 SendAsync 重载,

var content = new JsonContent(myObject);
// Update Content headers here
var request = new HttpRequestMessage {RequestUri = uri, Content = content };
// Update request headers here
_httpClient.SendAsync(request);
Run Code Online (Sandbox Code Playgroud)

几乎可以为任何媒体类型或任何数据源轻松创建派生内容类。我创建了从 HttpContent 派生的各种类。例如 FileContent、EmbeddedResourceContent、CSVContent、XmlContent、ImageContent、HalContent、CollectionJsonContent、HomeContent、ProblemContent。

就我个人而言,我发现它可以让我更好地控制我的有效载荷。