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

时间:2014-04-18 19:41:41

标签: asp.net json utf-8 asp.net-web-api httpclient

我有一个问题     HttpClient.PostAsJsonAsync()

除了" application / json"在" Content-Type"标题方法还添加" charset = utf-8"

所以标题看起来像这样:

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

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

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

解: 致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());
    }
}

3 个答案:

答案 0 :(得分: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);
}

本质上是这样的:

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

答案 1 :(得分:4)

为了更直接地控制您发送的有效负载,您可以创建派生的HttpContent类,而不是让您的对象传递给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);
    }
}

一旦你上了这门课,你就可以了,

var content = new JsonContent(myObject);
_httpClient.PostAsync(uri,content);

如果您需要更改任何内容标题,您可以在发送请求之前手动执行此操作。如果你需要处理任何请求标头,那么你使用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);

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

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

答案 2 :(得分:-1)

我更喜欢Darrel的答案,但对于我来说它仍然太复杂了。我用过这个:

public class ContentTypeSpecificStringContent : StringContent
{
    /// <summary>
    /// Ensure content type is reset after base class mucks it up.
    /// </summary>
    /// <param name="content">Content to send</param>
    /// <param name="encoding">Encoding to use</param>
    /// <param name="contentType">Content type to use</param>
    public ContentTypeSpecificStringContent(string content, Encoding encoding, string contentType)
        : base(content, encoding, contentType)
    {
        Headers.ContentType = new MediaTypeHeaderValue(contentType);
    }
}

毋庸置疑,您可以根据自己的需求调整适合自己的基类。希望能有所帮助。