I have a REST API written in C #. Method DoQuery send query to the database, and get json as response
public async Task<QueryResponseDto> DoQuery(string request)
{
return await _dbConnection.QuerySingleAsync<QueryResponseDto>("select web.json_request('" + request + "') as response;",commandTimeout:600);
}
...
[HttpPost]
[Route("DoQuery")]
public async Task<string> DoQuery([FromBody] object body)
{
var r = await _dataService.DoQuery(JsonSerializer.Serialize(body));
return r.response;
}
When I run query in database, I get correct json answer like this
[
{
"contractor":{
"ek2id":"91707d21-50f3-4aa4-8209-e80b963da99d",
"externalids":[
{
"externalsource":"SBL",
"externalid":"1-4OB8C75"
}
]
}
}
]
But when I run method DoQuery from PostMan I get escaped response like this
"[{\"contractor\":{\"ek2id\":\"91707d21-50f3-4aa4-8209-e80b963da99d\",\"externalids\":[{\"externalsource\":\"SBL\",\"externalid\":\"1-4OB8C75\"}]}}]"
How can I get normal unescaped response from REST API?
When you query the database it formats the JSON for you when it displays the output. The actual value in the database could be some UTF8, or similar encoding.
If escape is causing issue you could try storing actual UTF8 value for quotes in the string. But in both the cases you need to encode the response.
Related
With a simple C# AWS Lambda
public string FunctionHandler(string myParam1, ILambdaContext context)
{
return myParam1;
}
How should I pass parameters to an AWS Lambda function + API Gateway, via a browser GET request?
I'd like something like this for example:
https://[API ID].execute-api.[REGION].amazonaws.com/myFunc?myParam1=myValue1
In the browser it says {"message":"Internal Server Error"}
In the logs it says Error converting the Lambda event JSON payload to a string. JSON strings must be quoted, for example "Hello World" in order to be converted to a string: The JSON value could not be converted to System.String.
Without parameters it works, for example:
public string FunctionHandler(ILambdaContext context)
{
return Utf8Json.JsonSerializer.ToJsonString(context);
}
When sending a GET request in the browser https://[API ID].execute-api.[REGION].amazonaws.com/myFunc returns successfully {"AwsRequestId":"86ca2da9-438c-4865-8a0b-29d3ced37176","FunctionName":....
Ok I found a solution, instead of using the built-in parsing of parameters, it's possible to read a full JSON of parameters by reading a stream instead:
public string FunctionHandler(Stream requestStream, ILambdaContext context) { ... }
The requestStream here will have the parameters of GET/POST inside or a larger JSON, but have to be manually parsed. Note that the parameters may be sent b64 encoded (or probably also compressed). A good way would be to find a library which does this parsing.
In my case, I also write the consumer JS code, so I can ensure the parameters will always come in the same fashion so my problem is solved but if someone has knows a good library for this, please tell.
Example of a manual POST request data extraction which also supports b64 encoding:
public class StreamBody
{
public string body;
public bool isBase64Encoded;
}
public string FunctionHandler(Stream requestStream, ILambdaContext context)
{
using var sr = new StreamReader(requestStream);
var input = sr.ReadToEnd();
var sbody = Utf8Json.JsonSerializer.Deserialize<StreamBody>(input);
var body = !sbody.isBase64Encoded ? sbody.body : Encoding.UTF8.GetString(Convert.FromBase64String(sbody.body));
Background
I'm sending JSON in my body to my API controller but keep getting the following error.
{"":["Unexpected character encountered while parsing value: {. Path
'', line 1, position 1."]}
My HTTP request
HttpClient client = new HttpClient();
HttpRequest httpRequest;
HttpResponseMessage httpResponse = null;
httpRequest = new HttpRequest("", HostnameTb.Text, null);
var values = new Dictionary<string, string>
{
{ "APIKey", APIKeyTb.Text }
};
string json = JsonConvert.SerializeObject(values);
StringContent content = new StringContent(json.ToString(), Encoding.UTF8, "application/json");
httpResponse = client.PostAsync(HostnameTb.Text, content).Result;
var responseString = await httpResponse.Content.ReadAsStringAsync();
My Controller looks like this.
[HttpPost]
public void Post([FromBody] string value)
{
//Never gets here.
}
The Json in the body.
{"APIKey":"1283f0f8..."}
Question
I would prefer to use the .Net Core [From Body] functionality, rather than getting the content manually.
I would expect the JSON string to be available in the string Value parameter.
What am I missing?
ASP.NET Core tries to deserialize {"APIKey":"1283f0f8..."} from JSON into a string value, and fails, because it expects the input to be a valid JSON string.
In other words, if your body was "{\"APIKey\":\"1283f0f8...\"}" you would have the JSON string in the input variable as you expect.
In order to get the APIKey value without changing the HTTP request, create an input type:
public class Input
{
public string ApiKey { get; set; }
}
and use that as the input of your controller action:
[HttpPost]
public void Post([FromBody] Input input)
{
var apiKey = input.ApiKey;
// etc
}
Alternatively, change your HTTP request to send a string:
// ...
var content = new StringContent(JsonConvert.SerializeObject(json), Encoding.UTF8, "application/json");
// ...
Note the use of JsonConvert.SerializeObject() instead of ToString(); "foo".ToString() is still just "foo", while you want "\"foo\"".
That's not how this works. [FromBody] invokes a serializer to deserialize the request body. Then, the modelbinder attempts to bind that to the param. Here, it cannot do that because you're binding to a string, and the request body is a dictionary. Essentially what's happening under the hood (pseudo-code) is:
value = JsonConvert.DeserializeObject<string>(dictionaryAsJson);
You're getting a deserialization error from JSON.NET because it can't parse the JSON into a string.
If you want the value as a string, then you should post is as something like text/plain instead of application/json. Otherwise, you'll need to bind to a type that actually represents the JSON object coming in, which would be a Dictionary<string, string> here.
I had the same issue with ASP.NET Core 3.1. I was POSTing a JSON to my API controller that looked like:
public JsonResult Save([FromBody]MainDetails obj){ ... }
The problem in my case was that a property ChildDetails.StartDate of my MainDetails object was of type DateTime, and I was sending a null value in JSON. This was causing the deserialization to fail at the controller. I changed the property type to DateTime? from DateTime to make it work.
Basically, one needs to check and ensure that the JSON that you POST is valid for the target object to which you are deserializing it. If you have non-nullable properties for which the value sent in JSON is null, then your deserialization will fail (without telling you why).
Hope this helps.
I am sending xml/mathml as data in my AJAX request, and at the server side in C# I get this sort of text:
%3Cmath%3E%0A%20%20%20%20%3Cmrow%3E%0A%20%20%20%20%20%20%20%20%3Cmsub%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cmi%3Ex%3C%2Fmi%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cmtext%3E12%3C%2Fmtext%3E%0A%20%20%20%20%20%20%20%20%3C%2Fmsub%3E%0A%20%20%20%20%20%20%20%20
So, basically it is xml, but the xml basic characters are converted to url like characters, %20, %3E, %0A etc...
I have this POST method in my API controller:
[HttpPost]
public HttpResponseMessage PostUpload(HttpRequestMessage req)
{
string jsonContent = req.Content.ReadAsStringAsync().Result;
Utility.Utility.WriteLineToConsole("json data post: " + jsonContent);
return Request.CreateResponse(HttpStatusCode.OK, jsonContent);
}
The Utility function WriteLineToConsole() prints the jsonContent and the top text among the result.
How can i covert the string above to xml, i.e replace the url-like characters to xml characters?
Note: I am using MVC 4 / C# , jQuery AJAX, and both contentType and dataType are of type json. I want my data object to be like
data:{mathml: "<math>...</math>"}
HttpUtility.UrlDecode(thatString)
did the job
When I try to post a string to my web api, the value is null. I have tried wrapping it in quotes, but it is still null.
AngularJS code:
return $http.post("http://localhost:59437/api/Recaptcha/Post",
vcRecaptchaService.getResponse());
Web Api code:
[EnableCors("*", "*", "*")]
public class RecaptchaController : ApiController
{
public string Post([FromBody] string response)
{
return response;
}
}
I also am not sure how this even works because, i don't have a response in my form body. vcRecaptchaService.getResponse() just returns a response string and then I am going to send that to google's verify api to verify the recaptcha, so the [FromBody] part doesn't make sense to me if that is not part of the body
Your post call should be sending data in json format like {response: 'something'}
return $http.post("http://localhost:59437/api/Recaptcha/Post",
{ response: vcRecaptchaService.getResponse() } //data
);
Wrapping it in quotes worked, but I had to do it just like this:
return $http.post("http://localhost:59437/api/Recaptcha/Post",
'"' + vcRecaptchaService.getResponse() + '"'
);
I have following web api method:
public IHttpActionResult Get(int id)
{
var person = _personRepository.GetPersonByID(id);
if (person == null)
return NotFound();
return Ok<Person>(person);
}
And following client calling method:
var data = default(IEnumerable<T>);
var response = _client.GetAsync(relativeUri).Result;
response.EnsureSuccessStatusCode(); // Throw on error code.
if (response.IsSuccessStatusCode)
{
//string dataString = response.Content.ReadAsStringAsync().Result;
data = response.Content.ReadAsAsync<IEnumerable<T>>().Result;
}
else
{
//return response status code/reason phrase
}
after ReadAsAsync call is finished, data variable indicates a collection of type T with count matching returned rows but all objects (elements) are having null valued properties or empty.
Actual values are not being populated in properties.
Fiddler shows the JSON string. Even, ReadAsStringAsAsync() method returns JSON string.
Is there a better way to parse JSON into T type using one of ReadAsXXXX() methods?
Thanks,
-Jignesh
I just wanted to update that I have found the root cause of the issue that I was facing.
The code sample that I mentioned is actually the correct way of calling web api methods.
In my case, JSON string was formatted in Camel Casing at server side and at client side, default formtting was used.
this is server side code which was causing the issue:
var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
As soon as this was removed, it started working.
Clearly, ReadAsAsync method could not find the matching properties and therefore all values were being dropped.
Thanks,
-Jignesh