如何将对象传递给 HttpClient.PostAsync 并序列化为 JSON 正文?
How do I pass an object to HttpClient.PostAsync and serialize as a JSON body?
我正在使用 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
做到这一点呢?谢谢。
您问题的直接答案是:否。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,例如死锁,因此您要小心。
您需要将请求正文中的数据作为原始字符串而不是 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);
一个简单的解决方案是使用 NuGet 中的 Microsoft ASP.NET Web API 2.2 Client
。
然后您可以简单地执行此操作,它将 object 序列化为 JSON 并将 Content-Type
header 设置为 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);
现在有一个更简单的方法 .NET Standard
或 .NET Core
:
var client = new HttpClient();
var response = await client.PostAsync(uri, myRequestObject, new JsonMediaTypeFormatter());
注意: 为了使用 JsonMediaTypeFormatter
class,您需要安装 Microsoft.AspNet.WebApi.Client
NuGet 包,可以是直接安装,或通过 Microsoft.AspNetCore.App
.
等其他方式安装
使用HttpClient.PostAsync
的这个签名,你可以传入任何对象,JsonMediaTypeFormatter
会自动处理序列化等
有了响应,您可以使用HttpContent.ReadAsAsync<T>
将响应内容反序列化为您期望的类型:
var responseObject = await response.Content.ReadAsAsync<MyResponseType>();
新的 .NET 5 解决方案:
在 .NET 5 中,引入了一个名为 JsonContent
的新 class,它派生自 HttpContent
。 See in Microsoft docs
这个class包含一个名为Create()
的静态方法,它接受任意对象作为参数,顾名思义returns是JsonContent
的一个实例,然后您可以将其作为参数传递给 PostAsync
方法。
用法:
var myObject = new
{
foo = "Hello",
bar = "World",
};
JsonContent content = JsonContent.Create(myObject);
HttpResponseMessage response = await _httpClient.PostAsync("https://...", content);
@arad 好点。事实上我刚刚找到了这个扩展方法(.NET 5.0):
PostAsJsonAsync<TValue>(HttpClient, String, TValue, CancellationToken)
所以现在可以:
var data = new { foo = "Hello"; bar = 42; };
var response = await _Client.PostAsJsonAsync(_Uri, data, cancellationToken);
您有两种选择,具体取决于您编码的框架,如果您使用的是 .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;
}
public static async Task<string> Post(string param, string code, string subject, string description)
{
object mydata = new
{
code = code,
subject = subject,
description = description
};
var myContent = JsonConvert.SerializeObject(mydata);
var buffer = System.Text.Encoding.UTF8.GetBytes(myContent);
var byteContent = new ByteArrayContent(buffer);
byteContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
using (HttpClient client = new HttpClient())
{
using (HttpResponseMessage res = await client.PostAsync(baseURL + param, byteContent))
{
Console.WriteLine("Nico", res);
using (HttpContent content = res.Content)
{
string data = await content.ReadAsStringAsync();
if (data != null) { return data; }
}
}
}
return string.Empty;
}
我的其他形式
private async void button2_Click(object sender, EventArgs e) //POST
{
string param = "subject";
string code = txtCode.Text; //NC101
string subject = txtSubject.Text;
string description = txtDescription.Text;
var res = await RESTHelper.Post(param, code, subject, description);
txtRes.Text = res;
}
我正在使用 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
做到这一点呢?谢谢。
您问题的直接答案是:否。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,例如死锁,因此您要小心。
您需要将请求正文中的数据作为原始字符串而不是 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);
一个简单的解决方案是使用 NuGet 中的 Microsoft ASP.NET Web API 2.2 Client
。
然后您可以简单地执行此操作,它将 object 序列化为 JSON 并将 Content-Type
header 设置为 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);
现在有一个更简单的方法 .NET Standard
或 .NET Core
:
var client = new HttpClient();
var response = await client.PostAsync(uri, myRequestObject, new JsonMediaTypeFormatter());
注意: 为了使用 JsonMediaTypeFormatter
class,您需要安装 Microsoft.AspNet.WebApi.Client
NuGet 包,可以是直接安装,或通过 Microsoft.AspNetCore.App
.
使用HttpClient.PostAsync
的这个签名,你可以传入任何对象,JsonMediaTypeFormatter
会自动处理序列化等
有了响应,您可以使用HttpContent.ReadAsAsync<T>
将响应内容反序列化为您期望的类型:
var responseObject = await response.Content.ReadAsAsync<MyResponseType>();
新的 .NET 5 解决方案:
在 .NET 5 中,引入了一个名为 JsonContent
的新 class,它派生自 HttpContent
。 See in Microsoft docs
这个class包含一个名为Create()
的静态方法,它接受任意对象作为参数,顾名思义returns是JsonContent
的一个实例,然后您可以将其作为参数传递给 PostAsync
方法。
用法:
var myObject = new
{
foo = "Hello",
bar = "World",
};
JsonContent content = JsonContent.Create(myObject);
HttpResponseMessage response = await _httpClient.PostAsync("https://...", content);
@arad 好点。事实上我刚刚找到了这个扩展方法(.NET 5.0):
PostAsJsonAsync<TValue>(HttpClient, String, TValue, CancellationToken)
所以现在可以:
var data = new { foo = "Hello"; bar = 42; };
var response = await _Client.PostAsJsonAsync(_Uri, data, cancellationToken);
您有两种选择,具体取决于您编码的框架,如果您使用的是 .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;
}
public static async Task<string> Post(string param, string code, string subject, string description)
{
object mydata = new
{
code = code,
subject = subject,
description = description
};
var myContent = JsonConvert.SerializeObject(mydata);
var buffer = System.Text.Encoding.UTF8.GetBytes(myContent);
var byteContent = new ByteArrayContent(buffer);
byteContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
using (HttpClient client = new HttpClient())
{
using (HttpResponseMessage res = await client.PostAsync(baseURL + param, byteContent))
{
Console.WriteLine("Nico", res);
using (HttpContent content = res.Content)
{
string data = await content.ReadAsStringAsync();
if (data != null) { return data; }
}
}
}
return string.Empty;
}
我的其他形式
private async void button2_Click(object sender, EventArgs e) //POST
{
string param = "subject";
string code = txtCode.Text; //NC101
string subject = txtSubject.Text;
string description = txtDescription.Text;
var res = await RESTHelper.Post(param, code, subject, description);
txtRes.Text = res;
}