我正在尝试为HttpClient.PutAsJsonAsync<T>
写一个重载,该重载允许在每个请求上设置标头。查看该方法的源代码,它会在内部创建一个ObjectContent<T>
,我在下面尝试进行模拟。
但是,绑定(使用[FromBody] Form form
)时,我的目标服务器总是收到一个空的正文。
如果我将请求更改为StringContent
并手动序列化正文,则请求成功!两种实现之间有什么区别?
更奇怪的是,如果我在{em> await content.ReadAsStringAsync()
之前致电SendAsync
,那么它也有效!
我的想法可能是:
async Main()
我的环境是:
netcoreapp2.1
exe,可以在microsoft/dotnet:2.1-sdk-alpine
泊坞镜映像中运行。下面的代码是客户呼叫的精简版。
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; }
}