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


93

我正在使用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怎么办?我的phpRestAPI等待json输入,因此FormUrlEncodedContent应该raw正确发送json。但是我该怎么做Microsoft.Net.Http呢?谢谢。


如果我理解您的问题,您想发送JSON内容而不是表单编码的内容吗(并且通过扩展,您希望将匿名类型作为JSON序列化到该内容中)?
CodingGorilla

@CodingGorilla是匿名类型。
IlDrugo '16

3
作为一个侧面说明了未来的读者,不使用usingHttpClientaspnetmonsters.com/2016/08/2016-08-27-httpclientwrong
maxshuty

2
Microsoft的注释,为什么using不应该使用它:HttpClient is intended to be instantiated once and reused throughout the life of an application. The following conditions can result in SocketException errors: Creating a new HttpClient instance per request. Server under heavy load. Creating a new HttpClient instance per request can exhaust the available sockets. docs.microsoft.com/en-us/aspnet/web-api/overview/advanced/…–
Ogglas

Answers:


155

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

公共任务PostAsync(Uri requestUri,HttpContent内容)

因此,尽管您可以将传递objectPostAsync它,但它必须是类型,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像您在此处那样调用该属性可能会带来一些不良后果,例如死锁,因此您需要谨慎操作。


好的,很清楚。感谢您的回答。只是一个问题:POST, PUT, DELETE执行a时(通常是API return)TRUE,我将该方法声明为string,但是当我这样做时:return result;I get Can't Convert HttpResponseMessage in string:,是否应该更改方法声明?我需要字符串响应,因为在其他类方法中,我需要对其反序列化。
IlDrugo '16

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

抱歉,如果数据是类型的,是否需要执行此操作StringContent
MyDaftQuestions

1
@MyDaftQuestions我不确定您要问的是什么,但是您可以StringContent直接将传递给,PostAsync因为它源自HttpContent
CodingGorilla

@CodingGorilla,那我要的。谢谢您:)
MyDaftQuestions

67

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

var json = JsonConvert.SerializeObject(data); // or JsonSerializer.Serialize if using System.Text.Json

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

var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); // use MediaTypeNames.Application.Json in Core 3.0+ and Standard 2.1+

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

什么stringContent啊 就我而言,stringContent值是"\"\""。这是正确的值吗?
R15

是否有可能从您的C#代码中获取vb中的字符串结果?我发现这是非常相似....
gumuruh

42

一个简单的解决方案是使用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);

2
绝对可以使用PostAsJsonAsync
Kat Lim Ruiz

25

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

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

注意:为了使用JsonMediaTypeFormatter该类,您将需要安装Microsoft.AspNet.WebApi.ClientNuGet软件包,该软件包可以直接安装,也可以通过另一个安装,例如Microsoft.AspNetCore.App

使用的签名HttpClient.PostAsync,您可以传入任何对象,并且JsonMediaTypeFormatter会自动处理序列化等操作。

使用响应,可以HttpContent.ReadAsAsync<T>将响应内容反序列化为所需的类型:

var responseObject = await response.Content.ReadAsAsync<MyResponseType>();

1
这是什么版本的.net?我的版本在System.Net.Http命名空间中找不到“格式设置”
TemporaryFix

1
@Programmatic正如我提到的,您需要使用.NET Standard.NET Core。也许您正在使用.NET Framework?在我的项目中,从此处加载JsonMediaTypeFormatter:C:\ Program Files \ dotnet \ sdk \ NuGetFallbackFolder \ microsoft.aspnet.webapi.client \ 5.2.6 \ lib \ netstandard2.0 \ System.Net.Http.Formatting。 dll
肯·里昂

1
@Programmatic如果您已经在使用其中一种项目类型,则可能是您需要添加一个额外的NuGet包。我完全忘记了自动为我包含的内容。就我而言,它已包含在Microsoft.AspNetCore.App NuGet包中。
肯·里昂

1
我使用的是.NET Core,但我认为我的解决方案未设置为使用最新版本的c#语言。我更新了,它起作用了。谢谢
TemporaryFix

1
@Programmatic不客气。我很高兴听到你的工作!我在关于NuGet软件包的答案中添加了注释。
肯·里昂
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.