ObjectContent不起作用,但StringContent可以

时间:2018-11-12 22:24:05

标签: c# dotnet-httpclient

我正在尝试为HttpClient.PutAsJsonAsync<T>写一个重载,该重载允许在每个请求上设置标头。查看该方法的源代码,它会在内部创建一个ObjectContent<T>,我在下面尝试进行模拟。

但是,绑定(使用[FromBody] Form form)时,我的目标服务器总是收到一个空的正文。

如果我将请求更改为StringContent并手动序列化正文,则请求成功!两种实现之间有什么区别?

更奇怪的是,如果我在{em> await content.ReadAsStringAsync()之前致电SendAsync ,那么它也有效!

我的想法可能是:

  • JSON的序列化方式不同(但是我没有在任何地方配置任何Json.NET全局变量。)显而易见的问题是大小写不同,但是据我所知,JSON.net在解析时不区分大小写,而我服务器将使用JSON.net
  • 我不是在等待内容,而是在完全序列化之前发送内容。不过,我在代码中找不到任何未完成的任务,而入口点是标准的async Main()

我的环境是:

  • 客户端是一个简单的netcoreapp2.1 exe,可以在microsoft/dotnet:2.1-sdk-alpine泊坞镜映像中运行。
  • 服务器是.NET框架MVC5 WebApi,具有许多其他客户端可以调用的类似API

下面的代码是客户呼叫的精简版。

public static class UserUpdater
{
    public static async Task UpdateAsync(List<string> users)
    {
        using (var client = new HttpClient())
        {
            var form = new { Users = users };
            var headers = new Dictionary<string, string>
            {
                ["Authorization"] = "Bearer " // Real JWT here
            };

            var response = await client.PutAsJsonAsync(new Uri("http://localhost/api/app/v1/gateway-users"), form, headers);
            if (!response.IsSuccessStatusCode)
            {
                throw new InvalidOperationException("Response status code does not indicate success: " +
                                                    response.StatusCode + "\n\n" +
                                                    await response.Content.ReadAsStringAsync());
            }
        }
    }

    public static async Task<HttpResponseMessage> PutAsJsonAsync<T>(this HttpClient client, Uri requestUri, T value,
        IEnumerable<KeyValuePair<string, string>> headers, CancellationToken cancellationToken = default)
    {
        var content = new ObjectContent<T>(value, new JsonMediaTypeFormatter(), (MediaTypeHeaderValue)null);
        ////var content = new StringContent(JsonConvert.SerializeObject(value), Encoding.UTF8, "application/json"); // This works fine
        var message = MakeRequestMessage(HttpMethod.Put, requestUri, headers, content);
        return await client.SendAsync(message, cancellationToken);
    }

    private static HttpRequestMessage MakeRequestMessage(
        [NotNull] HttpMethod method,
        [NotNull] Uri requestUri,
        [CanBeNull] IEnumerable<KeyValuePair<string, string>> headers,
        [CanBeNull] HttpContent content = null)
    {
        var message = new HttpRequestMessage(method, requestUri);

        if (headers != null)
        {
            foreach (var header in headers)
            {
                message.Headers.Add(header.Key, header.Value);
            }
        }

        if (content != null)
        {
            message.Content = content;
        }

        return message;
    }

如果有帮助,这是服务器端(MVC5 WebApi):

    [Route("")]
    [ValidateModel]
    public IHttpActionResult Put([Required] [FromBody] GatewayUserCollectionForm form)
    {
        Ensure.NotNull(form, nameof(form)); // This throws since form is null

        this.manager.UpdateGatewayUsers(form.Users.ToList());
        return this.Ok();
    }

    public class GatewayUserCollectionForm
    {
        [Required]
        public List<string> Users { get; set; }
    }

0 个答案:

没有答案