How do I pass an object to HttpClient.PostAsync and serialize as a JSON body?
New .NET 5 Solution:
In .NET 5, a new class has been introduced called JsonContent
, which derives from HttpContent
. See in Microsoft docs
This class contains a static method called Create()
, which takes any arbitrary object as a parameter, and as the name implies returns an instance of JsonContent
, which you can then pass as an argument to the PostAsync
method.
Usage:
var myObject = new
{
foo = "Hello",
bar = "World",
};
JsonContent content = JsonContent.Create(myObject);
await _httpClient.PostAsync("https://...", content);
Even better, you can actually use the new PostAsJsonContentAsync
extension method to make this even more concise — see the docs for this.
Usage:
var myObject = new
{
foo = "Hello",
bar = "World",
};
await _httpClient.PostAsJsonAsync("https://...", content);
Thanks to @charlesthyer and @KonradViltersten for pointing this out.
A simple solution is to use Microsoft ASP.NET Web API 2.2 Client
from NuGet.
Then you can simply do this and it'll serialize the object to JSON and set the Content-Type
header to 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);
The straight up answer to your question is: No. The signature for the PostAsync
method is as follows:
public Task PostAsync(Uri requestUri, HttpContent content)
So, while you can pass an object
to PostAsync
it must be of type HttpContent
and your anonymous type does not meet that criteria.
However, there are ways to accomplish what you want to accomplish. First, you will need to serialize your anonymous type to JSON, the most common tool for this is Json.NET. And the code for this is pretty trivial:
var myContent = JsonConvert.SerializeObject(data);
Next, you will need to construct a content object to send this data, I will use a ByteArrayContent
object, but you could use or create a different type if you wanted.
var buffer = System.Text.Encoding.UTF8.GetBytes(myContent);
var byteContent = new ByteArrayContent(buffer);
Next, you want to set the content type to let the API know this is JSON.
byteContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
Then you can send your request very similar to your previous example with the form content:
var result = client.PostAsync("", byteContent).Result
On a side note, calling the .Result
property like you're doing here can have some bad side effects such as dead locking, so you want to be careful with this.
You need to pass your data in the request body as a raw string rather than FormUrlEncodedContent
. One way to do so is to serialize it into a JSON string:
var json = JsonConvert.SerializeObject(data); // or JsonSerializer.Serialize if using System.Text.Json
Now all you need to do is pass the string to the post method.
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);