如何将对象传递给HttpClient.PostAsync并序列化为JSON主体?

时间:2016-04-14 14:15:52

标签: c# json dotnet-httpclient

我正在使用System.Net.Http,我在网上找到了几个例子。我设法创建此代码以生成POST请求:

public static string POST(string resource, string token)
{
    using (var client = new HttpClient())
    {
        client.BaseAddress = new Uri(baseUri);
        client.DefaultRequestHeaders.Add("token", token);

        var content = new FormUrlEncodedContent(new[]
        {
             new KeyValuePair<string, string>("", "")
        });

        var result = client.PostAsync("", content).Result;
        string resultContent = result.Content.ReadAsStringAsync().Result;
        return resultContent;
    }
 }
一切正常。但是假设我希望将第三个参数传递给POST方法,一个名为data的参数。数据参数是这样的对象:

object data = new
{
    name = "Foo",
    category = "article"
};

如果不创建KeyValuePair,我怎么能这样做?我的php RestAPI等待json输入,因此FormUrlEncodedContent应正确发送raw json。但是如何使用Microsoft.Net.Http执行此操作?感谢。

7 个答案:

答案 0 :(得分:103)

您问题的直接答案是:否。PostAsync方法的签名如下:

  

public Task PostAsync(Uri requestUri,HttpContent content)

因此,虽然您可以将object传递给PostAsync,但它必须是HttpContent类型且您的匿名类型不符合该条件。

但是,有很多方法可以实现您想要完成的任务。首先,您需要将匿名类型序列化为JSON,最常见的工具是Json.NET。而这个代码非常简单:

var myContent = JsonConvert.SerializeObject(data);

接下来,您需要构建一个内容对象来发送此数据,我将使用ByteArrayContent对象,但您可以根据需要使用或创建其他类型。

var buffer = System.Text.Encoding.UTF8.GetBytes(myContent);
var byteContent = new ByteArrayContent(buffer);

接下来,您要设置内容类型以让API知道这是JSON。

byteContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");

然后,您可以使用表单内容发送与上一个示例非常相似的请求:

var result = client.PostAsync("", byteContent).Result

在旁注中,像你一样在这里调用.Result属性可以有一些bad side effects,例如死锁,所以你要小心这个。

答案 1 :(得分:35)

您需要将请求正文中的数据作为原始字符串而不是FormUrlEncodedContent传递。一种方法是将其序列化为JSON字符串:

var json = JsonConvert.SerializeObject(data);

现在您需要做的就是将字符串传递给post方法。

var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json");

var client = new HttpClient();
var response = await client.PostAsync(uri, stringContent);

答案 2 :(得分:24)

一个简单的解决方案是使用NuGet中的Microsoft ASP.NET Web API 2.2 Client

然后你可以简单地执行此操作,它会将对象序列化为JSON并将Content-Type标题设置为application/json; charset=utf-8

var data = new
{
    name = "Foo",
    category = "article"
};

var client = new HttpClient();
client.BaseAddress = new Uri(baseUri);
client.DefaultRequestHeaders.Add("token", token);
var response = await client.PostAsJsonAsync("", data);

答案 3 :(得分:15)

新的 .NET 5 解决方案:

在 .NET 5 中,引入了一个名为 JsonContent 的新类,它派生自 HttpContentSee in Microsoft docs

这个类有一个名为Create()的静态方法,它接受一个对象作为参数。

用法:

var myObject = new
{
    foo = "Hello",
    bar = "World",
};

JsonContent content = JsonContent.Create(myObject);

HttpResponseMessage response = await _httpClient.PostAsync("https://...", content);

答案 4 :(得分:10)

.NET Standard.NET Core现在有一种更简单的方法:

var client = new HttpClient();
var response = await client.PostAsync(uri, myRequestObject, new JsonMediaTypeFormatter());

注意::要使用JsonMediaTypeFormatter类,您需要安装Microsoft.AspNet.WebApi.Client NuGet软件包,该软件包可以直接安装,也可以通过诸如{ {1}}。

使用Microsoft.AspNetCore.App的签名,您可以传入任何对象,HttpClient.PostAsync将自动处理序列化等操作。

对于响应,您可以使用JsonMediaTypeFormatter将响应内容反序列化为所需的类型:

HttpContent.ReadAsAsync<T>

答案 5 :(得分:6)

@arad 好点子。事实上我刚刚发现了这个扩展方法(.NET 5.0):

PostAsJsonAsync<TValue>(HttpClient, String, TValue, CancellationToken)

来自https://docs.microsoft.com/en-us/dotnet/api/system.net.http.json.httpclientjsonextensions.postasjsonasync?view=net-5.0

现在可以:

var data = new { foo = "Hello"; bar = 42; };
var response = await _Client.PostAsJsonAsync(_Uri, data, cancellationToken);

答案 6 :(得分:0)

根据您编码的框架,您有两种选择,如果您使用的是 .Net 5,则可以执行 JsonContent.Create(yourObject);

或创建和扩展方法并在您的对象上调用它:

public static StringContent GetStringContent(this object obj)
{
    var jsonContent = JsonConvert.SerializeObject(obj);
    var contentString = new StringContent(jsonContent, Encoding.UTF8, "application/json");
    contentString.Headers.ContentType = new MediaTypeHeaderValue("application/json");

    return contentString;
}