Mark
Mark

Reputation: 21646

POSTing JsonObject With HttpClient From Web API

I'm trying to POST a JsonObject using HttpClient from Web API. I'm not quite sure how to go about this and can't find much in the way of sample code.

Here's what I have so far:

var myObject = (dynamic)new JsonObject();
myObject.Data = "some data";
myObject.Data2 = "some more data";

HttpClient httpClient = new HttpClient("myurl");
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

HttpResponseMessage response = httpClient.Post("", ???);

I think I need to cast my JsonObject as a StreamContent but I'm getting hung up on that step.

Upvotes: 443

Views: 660945

Answers (11)

pomber
pomber

Reputation: 23990

With the new version of HttpClient and without the WebApi package it would be:

var content = new StringContent(jsonObject.ToString(), Encoding.UTF8, "application/json");
var result = client.PostAsync(url, content).GetAwaiter().GetResult();

Or if you want it async:

var result = await client.PostAsync(url, content);

Upvotes: 699

Stefano Ronchese
Stefano Ronchese

Reputation: 29

the code over it in vb.net:

dim FeToSend as new (object--> define class)

Dim client As New HttpClient
Dim content = New StringContent(FeToSend.ToString(), Encoding.UTF8,"application/json")
content.Headers.ContentType = New MediaTypeHeaderValue( "application/json" )
Dim risp = client.PostAsync(Chiamata, content).Result

msgbox(risp.tostring)

Upvotes: 2

anthls
anthls

Reputation: 564

Using pomber's approach, I kept receiving a "400 Bad Request" response from an API I was POSTing my JSON request to (Visual Studio 2017, .NET 4.6.2). Eventually the problem was traced to the "Content-Type" header produced by StringContent() being incorrect (see https://github.com/dotnet/corefx/issues/7864).

tl;dr

Use pomber's answer with an extra line to correctly set the header on the request:

var content = new StringContent(jsonObject.ToString(), Encoding.UTF8, "application/json");
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var result = client.PostAsync(url, content).Result;

Upvotes: 40

user1752632
user1752632

Reputation: 1

Instead, do this:

var content = new StringContent(jsonObject.ToString(), Encoding.UTF8, "application/json");

var result = client.PostAsync(url, content).Result;

This is what I am using. It's safer

JsonContent content = JsonContent.Create(ObjectData);

HttpResponseMessage response = await client.PostAsync(url, content);

Hope it helps

Upvotes: -1

codejockie
codejockie

Reputation: 10912

In my case, I am using .NET 7.0; the StringContent did not work for me. I adapted some of the answers already provided to my use case. I used JsonContent to supply the body for the POST request.

var jsonContent = JsonContent.Create(new { ... });
var response = await _client.PostAsync("/", jsonContent);

Upvotes: 8

Manish Patil
Manish Patil

Reputation: 61

I Faced same issue i.e

var content = new StringContent(jsonObject.ToString(), Encoding.UTF8, "application/json"); 

gave

"400 Bad Request"

Serializing JsonObject separately and passing the string in StringContent() solved issue for me, no need to set Encoding.UTF8 separately.

Upvotes: 1

Hamit YILDIRIM
Hamit YILDIRIM

Reputation: 4549

I want to answer all in one response when doing this job as a note for all and myself:

According to Serez's answer HttpContent derived classes list as below https://stackoverflow.com/a/42380027/914284

HttpClient PostAsync has some background depending on the context you working on!

  • You can post data by the type that you want to send to server in cases Server context waits it as bellow
    [HttpPost]
    public async Task<IActionResult> Submit(MyModel model)
    [HttpPost]
    public async Task<IActionResult> Submit([FromForm] MyModel model)
    [HttpPost]
    public async Task<IActionResult> Submit([FromBody] MyModel model)

When writing FromForm or Body it has working as FromForm. FromBody needs json content otherwise it requires KeyValuePairs as rows. There is some implementations for both of them such as below:

For FromForm: I have used an extension

public static class HelperExtensions
    {
        public static FormUrlEncodedContent ToFormData(this object obj)
        {
            var formData = obj.ToKeyValue();

            return new FormUrlEncodedContent(formData);
        }

        public static IDictionary<string, string> ToKeyValue(this object metaToken)
        {
            if (metaToken == null)
            {
                return null;
            }

            // Added by me: avoid cyclic references
            var serializer = new JsonSerializer { ReferenceLoopHandling = ReferenceLoopHandling.Ignore };
            if (metaToken is not JToken token)
            {
                // Modified by me: use serializer defined above
                return ToKeyValue(JObject.FromObject(metaToken, serializer));
            }

            if (token.HasValues)
            {
                var contentData = new Dictionary<string, string>();
                foreach (var child in token.Children().ToList())
                {
                    var childContent = child.ToKeyValue();
                    if (childContent != null)
                    {
                        contentData = contentData.Concat(childContent)
                                                 .ToDictionary(k => k.Key, v => v.Value);
                    }
                }

                return contentData;
            }

            var jValue = token as JValue;
            if (jValue?.Value == null)
            {
                return null;
            }

            var value = jValue?.Type == JTokenType.Date ?
                            jValue?.ToString("o", CultureInfo.InvariantCulture) :
                            jValue?.ToString(CultureInfo.InvariantCulture);

            return new Dictionary<string, string> { { token.Path, value } };
        }
    }

For FromBody: Use any json converter library Newtonsoft or microsoft

using Newtonsoft.Json;

var jsonString = JsonConvert.SerializeObject(obj);

In both of them, content type should be defined according the requirement, for example for json (Write to header)

request.Headers.Accept.Clear();
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

or another usage

        using (var content = new StringContent(JsonConvert.SerializeObject(answer), System.Text.Encoding.UTF8, "application/json"))
        {
            var answerResponse = await client.PostAsync(url, content);
            //use await it has moved in some context on .core 6.0
        }

If you should use authorization on the context also you can provide authorization as below:

httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "Your Oauth token");

Upvotes: -1

Shojaeddin
Shojaeddin

Reputation: 2073

Thank you pomber but for

var result = client.PostAsync(url, content).Result;

I used

var result = await client.PostAsync(url, content);

because Result makes app lock for high request

Upvotes: 1

Matthew Steven Monkan
Matthew Steven Monkan

Reputation: 9160

If using Newtonsoft.Json:

using Newtonsoft.Json;
using System.Net.Http;
using System.Text;

public static class Extensions
{
    public static StringContent AsJson(this object o)
        => new StringContent(JsonConvert.SerializeObject(o), Encoding.UTF8, "application/json");
}

Example:

var httpClient = new HttpClient();
var url = "https://www.duolingo.com/2016-04-13/login?fields=";
var data = new { identifier = "username", password = "password" };
var result = await httpClient.PostAsync(url, data.AsJson())

Upvotes: 77

user3285954
user3285954

Reputation: 4749

Depending on your .NET version you could also use HttpClientExtensions.PostAsJsonAsync method.

https://msdn.microsoft.com/en-us/library/system.net.http.httpclientextensions.postasjsonasync.aspx

Upvotes: 90

carlosfigueira
carlosfigueira

Reputation: 87308

The easiest way is to use a StringContent, with the JSON representation of your JSON object.

httpClient.Post(
    "",
    new StringContent(
        myObject.ToString(),
        Encoding.UTF8,
        "application/json"));

Upvotes: 182

Related Questions