Posting JSON Array of Integers - c#

I am attempting to POST some JSON data to an API to add accounts.
The instructions specify the ids parameter can be: a string (comma-separated), or array of integers
I realize I could put comma delimited ids into the query string however I would like to POST this data as JSON as I may have a large number of these.
Here is what I have tried:
public static HttpClient GetHttpClient()
{
var property = Properties.Settings.Default;
HttpClient client = new HttpClient();
client.BaseAddress = new Uri(property.apiUrl);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Add("X-OrgSync-API-Key", property.apiKey);
return client;
}
HttpClient client = Api.GetHttpClient();
string json = "{\"ids\":[10545801,10731939]}";
var httpContent = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PostAsync($"{client.BaseAddress}/classifications/{classification.id}/accounts/add", httpContent);
It runs "successfully" but nothing actually gets set on the API server side.
Any ideas as to what I might be doing wrong here?
Additionally, any kind of tools/techniques etc., particularly in Visual Studio that would give me better visibility of the request/response traffic?
I know that this is possible as it correctly adds the account ids when I use a tool like Postman:

Regarding the Tools/Techniques, you can use Fiddler to capture the request and response on the fly to check if the Raw request is correct.
If you haven't used it before, have a look here for instructions on how to capture the requests and responses.

I was able to get the json string method working by changing the StringContent encoding type from Encoding.UTF8 to null OR Encoding.Default.
string json = "{\"ids\":[10545801,10731939]}";
var httpContent = new StringContent(json, Encoding.Default, "application/json");
var response = await client.PostAsync($"{client.BaseAddress}/classifications/{classification.id}/accounts/add", httpContent);
I also figured out a way to use an object containing an int array of ids with the Encoding.UTF8;
HttpClient client = Api.GetHttpClient();
var postData = new PostData {ids = new[] {10545801,10731939}};
var json = JsonConvert.SerializeObject(postData);
var httpContent = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PostAsync($"{client.BaseAddress}/classifications/{classification.id}/accounts/add", httpContent);
If you don't want to go to the trouble of creating a class just to store post data you can use an anonymous type:
var postData = new { ids = new[] {10545801,10731939}};
var json = JsonConvert.SerializeObject(postData);
var httpContent = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PostAsync($"{client.BaseAddress}/classifications/{classification.id}/accounts/add", httpContent);

Try below code it will work
using (var client= new HttpClient()) {
string json = "{\"ids\":[10545801,10731939]}";
var httpContent = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PostAsync($"{client.BaseAddress}/classifications/{classification.id}/accounts/add", httpContent);
// If the response contains content we want to read it!
if (response .Content != null) {
var responseContent = await response.Content.ReadAsStringAsync();
//you will get your response in responseContent
}

Related

WPF / C# Using variables in API POST

Following on from the following question
WPF / C# Submit button to POST API
I now want to amend the POST BODY to include Username and Password Variable.
The below is what I am using at the moment
var OktaUserName = ADAccountName;
var OktaPassword = Password;
var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://trial.okta.com/api/v1/authn");
request.Content = new StringContent("{\"username\":"+OktaUserName+",\"password\":"+OktaPassword+",\"options\": {\"multiOptionalFactorEnroll\": true,\"warnBeforePasswordExpired\": true}}", Encoding.UTF8, "application/json");
var response = await client.SendAsync(request);
var responseContent = await response.Content.ReadAsStringAsync();
MessageBox.Show("Alert", json, "OK");
MessageBox.Show(responseContent, "Message");
I expect that the username and password is pulled from the stored variables and then added to OKTA as a new user, however with the above I get an error
ErrorCode E000003 Error Summary The Request Body was not well-formed
Any help will be greatly appreciated
Thank you #Fildor, your answers helped.
My modified request.Content is as follows
request.Content = new StringContent("{\"username\":\""+ADAccountNameStr+"\",\"password\":\""+PasswordStr+"\",\"options\": {\"multiOptionalFactorEnroll\": true,\"warnBeforePasswordExpired\": true}}", Encoding.UTF8, "application/json");

Post from request body with HttpClient

Trying to consume a REST api using HttpClient. Im required to pass username and password through the body. Below is my code,Its however not posting the data values;
var data = new Dictionary<string, string>
{ {"username","username"},
{"password","password"}};
var jsonData = JsonConvert.SerializeObject(data);
HttpClient client2 = new HttpClient();
var requestContent2 = new StringContent(data.ToString(), Encoding.UTF8, "application/json");
client2.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", access_token);
HttpResponseMessage response2 = await client2.PostAsync(nitaauthapi, requestContent2);
HttpContent content2 = response2.Content;
string result2 = await content2.ReadAsStringAsync();
JObject jObject2 = JObject.Parse(result2);
string NONCE = jObject2["NONCE"].Value<string>();
Here, you correctly encode your data as JSON:
var jsonData = JsonConvert.SerializeObject(data);
Afterwards, you ignore your JSON-encoded data and instead send the string "System.Collections.Generic.Dictionary`2[System.String,System.String]" (= the output of data.ToString()) to your API endpoint:
var requestContent2 = new StringContent(data.ToString(), Encoding.UTF8, "application/json");
To fix this, use jsonData in your StringContent instead of data.ToString().
How to avoid such issues in the future: Pay attention to Visual Studio's hints. Visual Studio will highlight jsonData in a light grey color and add three dots underneath to inform you that something might be wrong with it:
Hovering over it will produce a tooltip telling you that the variable's value is unused.

Why does method MultipartFormDataContent.ReadAsStringAsync return different values before sending http-request and after its receiving?

I have such case: I compare hash of http-request content before sending and after receiving.
If content is multipart form data content, then hashes aren't equal because content differs.
This is how I build request content (.net 5):
var json = JsonSerializer.Serialize(streamsInfoToSend);
var jsonContent = new StringContent(json, Encoding.UTF8, JsonContent);
var multiPartContent = new MultipartFormDataContent();
multiPartContent.Add(jsonContent);
streamsToSend.ForEach(s =>
{
var ms = new MemoryStream(s);
multiPartContent.Add(new StreamContent(ms));
});
var body = await multiPartContent.ReadAsStringAsync(token);
This is how I read it after receiveng of request (.net framework 4.7):
var requestContent = await request.Content.ReadAsStringAsync();
Values of body and requestContent are different (requestContent's size is smaller).
Why?

HttpPost request not working when JSON string has HTML in

If this is a duplicate of any existing question, please let me know which post has a similar situation.
I am trying to call a POST API, which actually works perfectly from REST clients like POSTMAN.
When I try to call that API from C# using HttpClient, it only works if I do not use any HTML content in the request body.
Here is my code:
HttpClient client = new HttpClient();
string baseUrl = channel.DomainName;
client.BaseAddress = new Uri(baseUrl);
client.DefaultRequestHeaders
.TryAddWithoutValidation(
"Content-Type",
"application/x-www-form-urlencoded;charset=utf-8");
const string serviceUrl = "/api/create";
var jsonString = CreateApiRequestBody(model, userId, false);
var uri = new Uri(baseUrl + serviceUrl);
try
{
HttpResponseMessage response = await client.PostAsync(uri.ToString(), new StringContent(jsonString, Encoding.UTF8, "application/json"));
if (response.IsSuccessStatusCode)
{
Stream receiveStream = response.Content.ReadAsStreamAsync().Result;
StreamReader readStream = new StreamReader(receiveStream, Encoding.UTF8);
var str = readStream.ReadToEnd();
}
...
}
And my jsonString looks like:
{
\"user_id\":\"6\",
\"description\":\"<h2 style=\\\"font-style:italic;\\\"><u><font><font>Test Test Test </font></font></u></h2>\\n\\n<p style=\\\"font-style: italic;\\\">Hi it's a Test JOB</p>\\n\\n<p> </p>\"
}
When I use plain text in description tag, the API returns a valid response, but not with the HTML content in it.
I believe I might be missing some extra header or something else.
Any help will be greatly appreciated.
Have you tried using WebUtility.HtmlEncode() method?
Where you're setting the StringContent content, try using WebUtility.HtmlEncode(jsonString) to make it API-friendly.
Like this:
using System.Net;
HttpResponseMessage response =
await client.PostAsync(
uri.ToString(),
new StringContent(WebUtility.HtmlEncode(jsonString),
Encoding.UTF8,
"application/json"));
Don't forget to use System.Net
That will give you a safe (especially for APIs) HTML string to use in your request.
Hope this helps.

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.
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).Result;
Or if you want it async:
var result = await client.PostAsync(url, content);
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"));
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
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())
I don't have enough reputation to add a comment on the answer from pomber so I'm posting another answer. 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;
I spent hours trying to solve this.
But #anthls anwser saved my skin.
var data = new StringContent(JsonConvert.SerializeObject(new
{
abc = "jsjs",
xyz = "hhhh"
}));
data.Headers.ContentType = new MediaTypeHeaderValue("application/json"); // <--
var response = await client.PostAsync(url, data);
the code over it in vbnet:
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)
Hope this help
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
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.
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");

Categories