Hi I have a function that will expose to the RestAPI. I need to pass in a JSON string to be a defined class. I use the following class for JSON format:
public class Registrant : Guest
{
public int RegistrantID { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
public int EventID { get; set; }
public bool IsPrimary { get; set; }
}
And I have the following function in my controller:
public HttpResponseMessage Create(string id, [FromBody]Registrant registrant)
However When I pass in the JSON string the same structure, it could not deserialize correctly.
Is there anything wrong with it?
PS: my JSON string in request body:
{
"RegistrantID":"0",
"Email": "abc#abc.com",
"Phone": "123456789",
"EventID": "8",
"IsPrimary": "true",
"CustomerId": "12345678",
"FirstName": "abc",
"LastName": "def"
}
Update:
The problem is resolved by choosing Content-Type as Application/Json
Also, I took out the quotes on int and bool params it works fine.
Finally the api call look like this in project:
public HttpResponseMessage Create([FromUri]string id, [FromBody]Registrant registrant)
Related
The API I am working on requires a very complicated JSON object be passed in as a string, along with other values. So I created a class like this:
public class BURequest
{
public Guid ID { get; set; }
public string JSONStr { get; set; } --->JSON passed in as string
public string VersionName { get; set; }
}
The API controller has the following method:
public async Task<IActionResult> Check ([FromBody] BURequest testRequest)
However I kept getting "After parsing a value an unexpected character was encountered: c. Path 'BURequest', line 4, position 3."
Here is the JSON string:
{
"content_version": "1",
"date_created": "2020-10-06T13:52:15.288Z",
"date_updated": "2020-10-06T13:54:24.325Z",
"tools": {
"car": true,
"truck": true
}
}
Is there any way to get around this problem without having to create a class for the JSON object itself? It's a complicated object and has a huge number of properties. Thanks!
p.s.I've verified that the JSON string is valid using JSONLint as suggested below.
I would use JsonElement for this:
public class BURequest
{
public Guid ID { get; set; }
public JsonElement JSONStr { get; set; } --->JSON passed in as string
public string VersionName { get; set; }
}
And then just get the value:
testRequest.JSONStr.ToString()
The Json needs to be:
{
"JSONStr" : {
"content_version": "1",
"date_created": "2020-10-06T13:52:15.288Z",
"date_updated": "2020-10-06T13:54:24.325Z",
"tools": {
"car": true,
"truck": true
}
}
}
Just adding an answer to go with the comment on the question. Changing the type of the JSONStr property from string to JObject solves the problem.
I'm at my wit's end here. I think I just need another set of eyes.
Method Signature:
public async Task<IHttpActionResult> Post(ApiRequest request)
Model:
[SuppressMessage("ReSharper", "CollectionNeverUpdated.Global")]
[SuppressMessage("ReSharper", "AutoPropertyCanBeMadeGetOnly.Global")]
public class ApiRequest
{
[JsonProperty("allowLoadingToDataWarehouse")]
public bool AllowLoadingToDataWarehouse { get; set; }
[JsonProperty("initialDelay")]
public string InitialDelay { get; set; }
[JsonProperty("reportIds")]
public IEnumerable<string> ReportIds { get; set; }
[JsonProperty("reportTypeDelay")]
public string ReportTypeDelay { get; set; }
[JsonProperty("runType")]
[JsonConverter(typeof(StringEnumConverter))]
public ReportRunType RunType { get; set; }
[JsonProperty("userId")]
public string UserId { get; set; }
[JsonProperty("wwDelay")]
public string WWDelay { get; set; }
[JsonProperty("weeks")]
public IEnumerable<string> Weeks { get; set; }
}
Javascript:
var submitReportRequest = {
userId: userid,
reportIds: reportids,
runType: 'Custom',
weeks: selectedweeks,
initialDelay: $('#InitialDelay').val(),
reportTypeDelay: $('#ReportTypeDelay').val(),
wwDelay: $('#WWDelay').val(),
allowLoadingToDataWarehouse: $('#AllowLoadingToDataWarehouse').val()
};
$.post("/api/SubmitReport", JSON.stringify(submitReportRequest), function (data) {
alert('success');
});
Serialized Json From JavaScript Post:
{
"userId": "30",
"reportIds": [
"59",
"60",
"61",
"62",
"63",
"64"
],
"runType": "Custom",
"weeks": [
"201409",
"201410",
"201411",
"201412"
],
"initialDelay": "00:00:00",
"reportTypeDelay": "00:00:00",
"wwDelay": "00:00:00"
}
Quickwatch of Deserialized Object
Initially I had int and TimeSpan for the Ids and Delays, respectively, and those were not deserializing correctly. So I changed them all to strings, and they're still not deserializing correctly.
What am I doing wrong or missing?
Edit: After trying every combination of attributes, I finally decided to stick it into the Fiddler Composer. And it works. So something must be off with my JavaScript.
Turns out that shorthand JQuery post() method was setting the Content-Type attribute on the Request to application/x-www-form-urlencoded; charset=UTF-8 when it needed to be set to application/json; charset=UTF-8
I found by watching the Network traffic in Chrome, and by changing my javascript to this
answer.
After hours of attempts and research, I am asking for your help.
I am calling a public API which returns the same structure except for the datas returned.
For examples, the REST calls which retrieve stations and districts return those two JSON answers :
Stations response :
"response" : {
"status": { "#attributes": {"code": "0", "message": "OK"} },
"data" : {
"station": [{
"number": "stationId",
"name": "stationName",
"address": "stationAddress",
"state": "1",
"latitude": "stationLat",
"longitude": "stationLong",
"slotsavailable": "10",
"bikesavailable": "20",
"pos": "0",
"district": "stationDistrict",
"lastupdate": "2016-03-28T11:47:08+02:00"
}, {...}, ...]}
}
Districts response :
"response" : {
"status": { "#attributes": {"code": "0", "message": "OK"} },
"data" : { "district": [{"id": "districtId", "name": "districtName"}, {...}, ...] }
}
I am using a .NET 4.5/C# solution with Newtonsoft.Json to execute the call.
I want to make the object, mapped to the client response, generic so the execution of the call will be made as follow :
var result = await client.Execute<Response<ApiResponseDistrict>>(request);
var result = await client.Execute<Response<ApiResponseStation>>(request);
My first attempt was to make a non generic call (create a full object by returned datas) which was a success.
My second attempt was to created a generic object so I made the following classes using the JsonProperty of the library Newtonsoft :
public class ApiResponse<T>
{
[JsonProperty("response")]
public Response<T> Response { get; set; }
}
public class Response<T>
{
[JsonProperty("status")]
public Status Status { get; set; }
[JsonProperty("data")]
public Data<T> Data { get; set; }
}
public class Data<T>
{
public T ResponseData { get; set; }
}
public class ApiResponseDistrict
{
[JsonProperty("district")]
public List<District> Districts { get; set; }
}
public class District
{
[JsonProperty("id")]
public int Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
}
At this point, when I am executing the call the object Response is valorized and also its property Status with the value waited but the property Data is never valorized (null).
My third attempt was to continue on the second attempt but using the JsonObject of the Newtonsoft library which it's given (with the same result) :
[JsonObject("district")]
public class ApiResponseDistrict
{
public List<District> Districts { get; set; }
}
As I am new to Newtonsoft, I would like to know if it is possible to use generic classes, as I am trying to do, to mapped the object returned by the call or I have to create a complete object for each "data" returned ?
Thank you for your answer and explanations or clues for me to find the answer !
public class Response<T>
{
[JsonProperty("status")]
public Status Status { get; set; }
[JsonProperty("data")]
public Data<T> Data { get; set; }
}
public class Data<T>
{
public T ResponseData { get; set; }
}
This adds another layer between the data, so a response would look like this:
{
"Status": …,
"Data": {
"ResponseData": {
<The actual type T>
}
}
}
Instead, you want to remove that ResponseData level:
public class Response<T>
{
[JsonProperty("status")]
public Status Status { get; set; }
[JsonProperty("data")]
public T Data { get; set; }
}
So for example, for the JSON above, you would have a StationResponseData class:
public class StationResponseData
{
public List<Station> Stations
{ get; set; }
}
And then you would deserialize the JSON as Response<StationResponseData>. The Station class would then contain those properties for number, name, address, etc.
I have a web api method that looks like this:
[HttpPost]
[Route("messages")]
public IHttpActionResult Post(IEnumerable<Email> email)
{
AddToQueue(email);
return Ok("message added to queue");
}
My Email class looks like this currently:
public string Body { get; set; }
public string From { get; set; }
public string Template { get; set; }
public string To { get; set; }
public string Type { get; set; }
And I'm posting to my Post method using fiddler, like this:
User-Agent: Fiddler
Host: localhost:3994
Content-Length: 215
Content-Type: application/json; charset=utf-8
[
{"Body":"body","From":"from","To":"to","Template":"template"},
{"Body":"body1","From":"from1","To":"to1","Template":"template1"},
{"Body":"body2","From":"from2","To":"to2","Template":"template2"}
]
This works fine. However, I want to be able to add a Dictionary to my Email class, so it will look like this:
public string Body { get; set; }
public string From { get; set; }
public string Template { get; set; }
public string To { get; set; }
public string Type { get; set; }
public Dictionary<string, string> HandleBars { get; set; }
And I changed my request to look like this:
[{
"Body": "body",
"From": "from",
"To": "to",
"Template": "template",
"HandleBars": [{
"something": "value"
}]
},
{
"Body": "body1",
"From": "from1",
"To": "to1",
"Template": "template1"
},
{
"Body": "body2",
"From": "from2",
"To": "to2",
"Template": "template2"
}]
However, when the Post method receives this, all the Email fields are populated, except for the HandleBars dictionary. What do I have to do in order to pass it in correctly? Is my json structured incorrectly?
The default JsonFormatter is unable to bind Dictionary from Javascript Array because it doesn't define a key to each item.
You need to use an Object instead:
"HandleBars": {
"something": "value"
}
You should have
{
"Body": "body",
"From": "from",
"To": "to",
"Template": "template",
"HandleBars": [
{ key: 'key1', value: 'something'}
]
}
I've been stuck on this for awhile. I have a JSON response sending me keys that include periods. For example: "cost_center.code"
How can I get this into my object? I'm not getting any errors but the value is just coming in as null and isn't being deserialized into my class.
Here's my classes:
public class Result
{
public string company { get; set; }
public string first_name { get; set; }
public string email { get; set; }
public string employee_id { get; set; }
public string last_name { get; set; }
[DeserializeAs(Name="cost_center.code")]
public string cost_center { get; set; }
}
public class RootObject
{
public List<Result> result { get; set; }
}
Here's the JSON response:
{
"result": [
{
"company": "My Company",
"first_name": "First",
"email": "example#fakeaddress.com",
"employee_id": "123456789",
"last_name": "Last",
"cost_center.code": "12345"
}
]
}
I execute with:
var response = client.Execute<List<RootObject>>(request);
// this returns null
Console.WriteLine(response.Data[0].result[0].cost_center);
// all other values return fine ex:
Console.WriteLine(response.Data[0].result[0].company);
I've tried both with and without the DeserializeAs. I'm not sure its even working. Am I using this property incorrectly? Is it a container issue with the List?
Edited and accepted the answer below to use JsonProperty. For others who may come along this was the solution.
Added JSON.net nuget.
using Newtonsoft.Json;
Set the JsonProperty as described:
[JsonProperty("cost_center.code")]
Changed my execute to:
var response = client.Execute(request);
Then deserialized it like this:
var jsonResponse = JsonConvert.DeserializeObject<RootObject>(response.Content);
Afterwards I can access the value:
Console.WriteLine(jsonResponse.result[0].CostCenter
Do the following with properties having period in their names :
[JsonProperty("cost_center.code")]
public string CostCenter{ get; set; }
It should work
If you want to user RestSharp natively or couldn't get the Newtonsoft.Json.JsonSerializer support to work (which I couldn't), they just added support for proper deserialization of properties with dots in their names as of 106.1.0.
See my response here: Accessing properties with a dot in their name