Reputation: 2069
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.
Upvotes: 172
Views: 443465
Reputation: 21
System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
Use this
Upvotes: 0
Reputation: 19842
Update: If you're using .NET 5 or newer, use this solution.
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.
Upvotes: 220
Reputation: 12695
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 obj = new
{
foo = "Hello",
bar = "World",
};
JsonContent content = JsonContent.Create(obj);
await client.PostAsync("https://...", content);
Even better, you can actually use HttpClient
's new PostAsJsonAsync
extension method to make this as concise as possible — see the docs for this.
Usage:
var obj = new
{
foo = "Hello",
bar = "World",
};
await client.PostAsJsonAsync("https://...", obj);
Upvotes: 130
Reputation: 4440
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 StringContent
instance to the PostAsync
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);
Upvotes: 100
Reputation: 655
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;
}
in my other form
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;
}
Upvotes: 0
Reputation: 61
You have two options depending on which framework are you coding, you could just do JsonContent.Create(yourObject);
if you are on .Net 5
or create and extension method and call it on your object:
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;
}
Upvotes: 5
Reputation: 402
@arad good point. In fact I just found this extension method (.NET 5.0):
PostAsJsonAsync<TValue>(HttpClient, String, TValue, CancellationToken)
So one can now:
var data = new { foo = "Hello"; bar = 42; };
var response = await _Client.PostAsJsonAsync(_Uri, data, cancellationToken);
Upvotes: 25
Reputation: 1365
There's now a simpler way with .NET Standard
or .NET Core
:
var client = new HttpClient();
var response = await client.PostAsync(uri, myRequestObject, new JsonMediaTypeFormatter());
NOTE: In order to use the JsonMediaTypeFormatter
class, you will need to install the Microsoft.AspNet.WebApi.Client
NuGet package, which can be installed directly, or via another such as Microsoft.AspNetCore.App
.
Using this signature of HttpClient.PostAsync
, you can pass in any object and the JsonMediaTypeFormatter
will automatically take care of serialization etc.
With the response, you can use HttpContent.ReadAsAsync<T>
to deserialize the response content to the type that you are expecting:
var responseObject = await response.Content.ReadAsAsync<MyResponseType>();
Upvotes: 33
Reputation: 3925
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);
Upvotes: 58