Receiving json as string always null - c#

With an endpoint like this:
[HttpPost("[action]")]
public async Task<ActionResult> Import([FromBody]string request)
{
var list = JsonConvert.DeserializeObject<List<RequestQuote>>(request);
return NoContent();
}
request always seems to be null. It worked for a little while earlier today but not sure what changed.
Here is the client side where I do the call.
var json = JsonConvert.SerializeObject(payload);
var data = new StringContent(json, Encoding.UTF8, "application/json");
var response = client.PostAsJsonAsync($"{endpoint}/api/v1.0/BatchImport/Import", data);
Payload is a List
Even when using
Import([FromBody] List<RequestQuote> request)
I get the same issue.

There is a bug in the code, the data is serialized twice, the second time when you use PostAsJsonAsync. Try this
var json = JsonConvert.SerializeObject(payload);
var data = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PostAsync($"{endpoint}/api/v1.0/BatchImport/Import", data);
if (response.IsSuccessStatusCode)
{
var stringData = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<object>(stringData);
}
and action should be
public async Task<ActionResult> Import([FromBody] List<RequestQuote> request)

If your controller has the [ApiController] attribute, you can put the data type you want to parse as the parameter of the method. I believe what is happening is that your program is trying to parse the JSON to a string type, which isn't what you want. You can try the code below, which should achieve what you're looking for.
[HttpPost("[action]")]
public async Task<ActionResult> Import([FromBody]List<RequestQuote> list)
{
// The parsed object should now be available here as "list"
return NoContent();
}
Alternatively, this post suggests pulling the body of the request directly. Either solution should be valid.

Related

The PostAsync in HttpClient doesn't send data to my webapi

I've created a HttpClient instance to invoke an API with post method.
using (var client = new HttpClient())
{
var person = new Stu();
person.ApplicantId = "48751889-D86E-487B-9508-000EAB65F11F";
var json = JsonConvert.SerializeObject(person);
var data = new StringContent(json, Encoding.UTF8, "application/json");
var url = "http://localhost:52085/api/CollegeService/IsCoolegeStudent";
// var client = new HttpClient();
var response = await client.PostAsync(url, data);
string result = response.Content.ReadAsStringAsync().Result;
Console.WriteLine(result);
}
public class Stu
{
public string ApplicantId { get; set; }
}
When I check my API out , I receive ApplicantId of my object is Null.
I cant not figure out why ApplicantId is Null.
Finally I've changed my [FromForm] to[FromBody] in my API and it worked correctly but it stuck on this line var response = await client.PostAsync(url, data);and doesn't go on.
the await keyboard make my app stuck ,I've changed it this way
var response = await client.PostAsync(url, data).ConfigureAwait(false);
but I didn't figure it out why it cause this problem.
If you using FromForm attribute, you should use FormUrlEncodedContent instead of StringContent as content type when you send POST message. If you still want send json - change FromForm at IsCoolegeStudent method to FromBody.

Error converting JSON response from backend to type with JsonConvert.DeserializeObject

So I am having this weird problem with deserializing a response from my BackEnd, The request works fine and the BackEnd succesfully responds with a result.
This is the error I get:
'Error converting value "{"Succes":true,"AuthKey":"$2a$13..."}" to type 'FrontEnd.LoginUserResponse'. Path '', line 1, position 96.'
The code I am using to make the HTTP call and deserialize the string:
public async Task<bool> loginUser(LoginUserData login)
{
HttpContent httpContent = new StringContent(JsonConvert.SerializeObject(login), Encoding.UTF8);
httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
HttpResponseMessage responseMessage = await httpClient.PostAsync("http://ip/webBackEnd/api/user/login", httpContent);
string response2 = responseMessage.Content.ReadAsStringAsync().Result;
LoginUserResponse response = JsonConvert.DeserializeObject<LoginUserResponse>(response2);
if (response.Succes)
{
return true;
}
else { return false; }
}
I tried making a response2 to check the value and I have noticed it does something weird with 3 backslashes. This might be the reason why this is occuring.
This is response2 that visual studio shows when I click the magnifying glass:
"{\"Succes\":true,\"AuthKey\":\"$2a$11$tQCw4zGGd2J2fXAxAN68Ruu3xheTuMKq4EHbeLtc9DAa2rgzJe8bS\"}"
When I hover on visual studio:
https://imgur.com/a/jUyLz6d
This is the Class that it is converting to
public class LoginUserResponse
{
[JsonProperty("succes")]
public bool succes { get; set; }
[JsonProperty("authkey")]
public string authkey { get; set; }
}
The Backend code:
[HttpPost]
[Route("login")]
public string Login([FromBody]LogInData logInData)
{
IReadUser.LogInRequest request = new IReadUser.LogInRequest(logInData);
IReadUser.LogInResponse backResponse = readUser.logIn(request);
LogInResponse response = new LogInResponse();
response.succes = backResponse.Succes;
response.authkey = backResponse.AuthKey;
return JsonConvert.SerializeObject(response);
}
EDIT // SOLUTION
Ok so, the front-end was fine, it was my backend code sending a double serialised string. I used
return JsonConvert.SerializeObject(response);
When I also could have used
return response;
So if you every get an error like this, it's probably the backend doubling up on the serialization.
Thanks for all the help!
Couple of things:
1. you should await responseMessage.Content.ReadAsStringAsync():
public async Task<bool> loginUser(LoginUserData login)
{
var httpContent = new StringContent(JsonConvert.SerializeObject(login), Encoding.UTF8);
httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var responseMessage = await httpClient.PostAsync("http://ip/webBackEnd/api/user/login", httpContent);
var response2 = await responseMessage.Content.ReadAsStringAsync();
var response = JsonConvert.DeserializeObject<LoginUserResponse>(response2);
return response.Succes
}
And 2. Based on your image it looks like the response from your backing service is being serialized twice.
1:
"{\"Succes\":true,\"AuthKey\":\"$2a$11$tQCw4zGGd2J2fXAxAN68Ruu3xheTuMKq4EHbeLtc9DAa2rgzJe8bS\"}"
2:
"\"{\\\"Succes\\\":true,\\\"AuthKey\\\":\\\"$2a$11$tQCw4zGGd2J2fXAxAN68Ruu3xheTuMKq4EHbeLtc9DAa2rgzJe8bS\\\"}\""
now to deserialize you have to do it twice
var s = JsonConvert.DeserializeObject<string>(response2);
var response = JsonConvert.DeserializeObject<LoginUserResponse>(s);
Probably best to fix the service if that's actually what is happening

Post using HttpClient & Read HttpResponseMessage status

I am posting to an API using HttpClient and getting back the HttpResponseMessage.
I am reading the status code from the reply but I it's always 200
Posting:
var json = JsonConvert.SerializeObject(loginDto);
var stringContent = new StringContent(json, Encoding.UTF8, "application/json");
var client = new HttpClient();
var response = await client.PostAsync("http://localhost:57770/api/Account/Login", stringContent);
I am replying from API the HttpResponseMessage:
return new HttpResponseMessage(HttpStatusCode.Unauthorized);
But when I read the response, it's always 200
How can I achieve this?
Asp.Net Core no longer recognizes HttpResponseMessage as part of the pipeline. This means it will be treated like any other returned model and serialized as content. Hence the 200 OK status.
The API controller action should return IActionResult derived result.
[HttpPost]
public IActionResult SomeAction(...) {
//...
return StatusCode((int)HttpStatusCode.Unauthorized); //401
//...
}
Or just use
return Unauthorized();
which is derived from StatusCodeResult and is used a short hand to replace the code shown above.
Reference ControllerBase.Unauthorized.

c# webapi post() and post([FromBody])

I'm building an webapi in c# to be called by an outside server.
let's say my API address is www.server.com/webapi/service1
when I set the address above in the app that will use it, it sends a simple POST with an empty body to service1 and waits for a specific KEY as response (in body), like an authentication. ok.
the same service1 can be called, using POST too, passing a raw JSON in the body, and I'm using the [FromBody] attribute to get the body and process.
I tried this to manage the empty POST call and the call with body data:
[HttpPost]
[Route("webapi/service1")]
public HttpResponseMessage Post()
{
var resp = new HttpResponseMessage(HttpStatusCode.OK);
resp.Content = new StringContent(TokenKey.ToString(), System.Text.Encoding.UTF8, "text/html");
return resp;
}
[HttpPost]
[Route("webapi/service1")]
public async Task<HttpResponseMessage> Post([FromBody] RetornoChat retornoChat)
{
await closedChat(retornoChat); //process body
return resp;
}
but it was not working.I manage a workaround like the code below, I check if the class in [FromBody] is empty, if this is the case return the special string to validate and finish, if there is a body then get the data validate and process. I'm wondering if there is a better solution.
I really thought that the solution was to double the post method and when there was a body it would call the post with the [frombody] and when there is no body it would go to the empty post.
[HttpPost]
[Route("webapi/service1")]
public async Task<HttpResponseMessage> Post([FromBody] RetornoChat retornoChat)
{
var resp = new HttpResponseMessage(HttpStatusCode.OK);
resp.Content = new StringContent(TokenKey.ToString(), System.Text.Encoding.UTF8, "text/html");
if (retornoChat == null)
{
}
else
{
//get the body data and process
}
return resp;
}
Thanks in advance for your time!

How can I get JSON data from Google API and store it in a variable?

I am trying to send an Http Get message to the Google location Api which is supposed to have Json data such as this
https://maps.googleapis.com/maps/api/geocode/json?address=Los%20Angeles,CA=AIzaSyDABt
as you noticed the response is in Json. I want to give a a Http Call to that URL and save the Json content in a variable or string. My code does not give out any errors but it is also not returning anything
public async System.Threading.Tasks.Task<ActionResult> GetRequest()
{
var client = new HttpClient();
HttpResponseMessage response = await client.GetAsync("https://maps.googleapis.com/maps/api/geocode/json?address=Los%20Angeles,CA=AIzaSyDABt");
string data = response.Content.ToString();
return data;
}
I want to send out a Get Request using HttpClient() or anything that will send out the URL request and then save that content into a string variable . Any suggestions would be appreciated, again my code gives no errors but it is not returning anything.
Use ReadAsStringAsync to get the json response...
static void Main(string[] args)
{
HttpClient client = new HttpClient();
Task.Run(async () =>
{
HttpResponseMessage response = await client.GetAsync("https://maps.googleapis.com/maps/api/geocode/json?address=Los%20Angeles,CA=AIzaSyDABt");
string responseString = await response.Content.ReadAsStringAsync();
Console.WriteLine(responseString);
});
Console.ReadLine();
}
If you use response.Content.ToString() it is actually converting the datatype of the Content to string so you will get System.Net.Http.StreamContent
Try this.
var client = new HttpClient();
HttpResponseMessage httpResponse = await client.GetAsync("https://maps.googleapis.com/maps/api/geocode/json?address=Los%20Angeles,CA=AIzaSyDABt");
string data = await httpResponse.Content.ReadAsStringAsync();
How about using the Json framework for .NET powered by Newtonsoft ?
You can try to parse your content to a string with this.
Well, your code can be simplified:
public async Task<ActionResult> GetRequest()
{
var client = new HttpClient();
return await client.GetStringAsync("https://maps.googleapis.com/maps/api/geocode/json?address=Los%20Angeles,CA=AIzaSyDABt");
}
However...
My code does not give out any errors but it is also not returning anything
This is almost certainly due to using Result or Wait further up the call stack. Blocking on asynchronous code like that causes a deadlock that I explain in full on my blog. The short version is that there is an ASP.NET request context that only permits one thread at a time; await by default will capture the current context and resume in that context; and since Wait/Result is blocking a thread in the request context, the await cannot resume executing.
Try this
public async static Task<string> Something()
{
var http = new HttpClient();
var url = "https://maps.googleapis.com/maps/api/geocode/json?address=Los%20Angeles,CA=AIzaSyDABt";
var response = await http.GetAsync(url);
if (response.IsSuccessStatusCode)
{
var result = await response.Content.ReadAsStringAsync();
result = JsonConvert.DeserializeObject<string>(result);
return result;
}
return "";
}
var result = Task.Run(() => Something()).Result;

Categories

Resources