How do I pass an object to HttpClient.PostAsync and serialize as a JSON body?

IlDrugo picture IlDrugo · Apr 14, 2016 · Viewed 218.7k times · Source

I'm using System.Net.Http, I found several examples on the web. I managed to create this code for make a POST request:

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;
    }
 }

all working fine. But suppose that I want pass a third param to the POST method, a param called data. The data param is an object like this:

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

how can I do that without create the KeyValuePair? My php RestAPI wait a json input, so the FormUrlEncodedContent should send the raw json correctly. But how can I do this with Microsoft.Net.Http? Thanks.

Answer

CodingGorilla picture CodingGorilla · Apr 14, 2016

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.