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

IlD*_*ugo 73 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;
    }
 }
Run Code Online (Sandbox Code Playgroud)

一切正常.但是假设我想要将第三个参数传递给POST方法,这个参数叫做data.数据参数是这样的对象:

object data = new
{
    name = "Foo",
    category = "article"
};
Run Code Online (Sandbox Code Playgroud)

如何在不创建的情况下做到这一点KeyValuePair?我的php RestAPI等待json输入,所以FormUrlEncodedContent应该raw正确发送json.但我怎么能这样做Microsoft.Net.Http呢?谢谢.

Cod*_*lla 123

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

public Task PostAsync(Uri requestUri,HttpContent内容)

因此,虽然您可以传递objectPostAsync它,但它必须是类型,HttpContent并且您的匿名类型不符合该条件.

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

var myContent = JsonConvert.SerializeObject(data);
Run Code Online (Sandbox Code Playgroud)

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

var buffer = System.Text.Encoding.UTF8.GetBytes(myContent);
var byteContent = new ByteArrayContent(buffer);
Run Code Online (Sandbox Code Playgroud)

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

byteContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
Run Code Online (Sandbox Code Playgroud)

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

var result = client.PostAsync("", byteContent).Result
Run Code Online (Sandbox Code Playgroud)

在旁注,调用.Result属性就像你在这里做的那样会产生一些不好的副作用,比如死锁,所以你要小心这个.

  • 如果您需要反序列化响应主体,则以问题的方式返回字符串(使用`result.Content.ReadAsStringAsync()`)就可以了。根据您的应用程序结构,如果您需要检查标头以确定内容类型(例如XML或JSON),则直接返回Content对象可能更好。但是,如果您“知道”它总是要返回JSON(或其他格式),那么只需将响应主体作为字符串返回就可以了。 (2认同)

elo*_*los 49

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

var json = JsonConvert.SerializeObject(data);
Run Code Online (Sandbox Code Playgroud)

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

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

var client = new HttpClient();
var response = await client.PostAsync(uri, stringContent);
Run Code Online (Sandbox Code Playgroud)

  • 请注意,`HttpStringContent`是一个Windows运行时类,可能并不总是可用.请参阅[此处]的要求部分(https://msdn.microsoft.com/en-us/library/windows/apps/windows.web.http.httpstringcontent.aspx). (3认同)
  • `new StringContent(json,UnicodeEncoding.UTF8,"application/json")` (3认同)

try*_*dis 28

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

然后你可以简单地执行此操作,并将对象序列化为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);
Run Code Online (Sandbox Code Playgroud)

  • 绝对可以使用 PostAsJsonAsync (4认同)

Ami*_*adi 19

新的 .NET 5 解决方案:

在 .NET 5 中,引入了一个名为 的新类JsonContent,它派生自HttpContent. 在 Microsoft 文档中查看

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

用法:

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

JsonContent content = JsonContent.Create(myObject);

HttpResponseMessage response = await _httpClient.PostAsync("https://...", content);
Run Code Online (Sandbox Code Playgroud)


Ken*_*yon 14

There's now a simpler way with .NET Standard or .NET Core:

var client = new HttpClient();
var response = await client.PostAsync(uri, myRequestObject, new JsonMediaTypeFormatter());
Run Code Online (Sandbox Code Playgroud)

NOTE: In order to use the JsonMediaTypeFormatter class, you will need to install the Microsoft.AspNet.WebApi.Client NuGet package, which can be installed directly, or via another such as Microsoft.AspNetCore.App.

Using this signature of HttpClient.PostAsync, you can pass in any object and the JsonMediaTypeFormatter will automatically take care of serialization etc.

With the response, you can use HttpContent.ReadAsAsync<T> to deserialize the response content to the type that you are expecting:

var responseObject = await response.Content.ReadAsAsync<MyResponseType>();
Run Code Online (Sandbox Code Playgroud)


小智 9

@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);
Run Code Online (Sandbox Code Playgroud)