Response Content not Hydrating Object - c#

I'm calling an API in the Controller of a MVC Core app as follows:
HttpContent httpContent = new StringContent(string.Empty, Encoding.UTF8, "text/plain");
HttpResponseMessage response = await client.PostAsync("api/users", httpContent);
if (response.IsSuccessStatusCode) {
User userJson = await response.Content.ReadFromJsonAsync<User>();
string responseContent = await response.Content.ReadAsStringAsync();
The value of responseContent is:
"{
\"actionName\":\"GetUser\",
\"routeValues\":{\"id\":\"30131055-9ff0-472f-a147-69e76f7aac77\"},
\"value\":{\"uid\":\"a36065bd-9d88-4ea3-f04d-08d98cfa8b83\",
\"email\":\"example#example.org\",
\"active\":true,\"created\":\"2021-10-12T19:49:16.0054897Z\",
\"updated\":\"2021-10-12T19:49:16.0054899Z\"},\"formatters\":[],
\"contentTypes\":[],
\"statusCode\":201
}"
I wasn't expecting this type of formatted content, I was expecting JSON, but I can see my the values for my User object in the "value" section.
My User object properties of uid, email, active, created, and updated are all public properties with get/set methods.
So I can see that my data is there, but when I try to deserialize the response to the User object I just see the default values after instantiation.
I feel like I'm missing something simple.

Your User class appears not to match the response json, you can either create the class structure that matches the response like this
public class RouteValues
{
public string id { get; set; }
}
public class Value //your user class
{
public string uid { get; set; }
public string email { get; set; }
public bool active { get; set; }
public DateTime created { get; set; }
public DateTime updated { get; set; }
}
public class Response
{
public string actionName { get; set; }
public RouteValues routeValues { get; set; }
public Value value { get; set; }
public List<object> formatters { get; set; }
public List<object> contentTypes { get; set; }
public int statusCode { get; set; }
}
and deserialize to the Response class and access the value object which is the equivalent to your user object or deserialize by specifying the key which does contain your user object, that being the value key.

Christian Franco noticed that the items in the object being return matched CreatedAtActionResult which the API I was calling was returning instead of the values I expected. This explains the odd behavior I was seeing.

Related

RestSharp not deserializing a string (always null)

I currently tried to get serialized response from a RestSharp PostAsync call like in
var responseData = Client.PostAsync<Data>(request).Result;
Now, this is what I receive:
{
"status":1,
"success":"message transmitted",
"available":19215,
"message_ids":"26684730:56798"
}
and this is the "Data" class:
public class Data
{
[JsonProperty("status")]
public int Status { get; set; }
[JsonProperty("success")]
public string Success { get; set; }
[JsonProperty("available")]
public int Available { get; set; }
[JsonProperty("message_ids")]
public string MessageIds { get; set; }
[JsonProperty("error")]
public string Error { get; set; }
}
I don't know why, but the property message_ids is always null!?
May this be caused by the : in the string, and my this be a bug in RestSharp?
Here is what "Data" looks like:
for restsharp you need JsonPropertyName attribute
[JsonPropertyName("message_ids")]
public string MessageIds { get; set; }
or if you want to use JsonProperty you will have to use Newtonsoft.Json
var response = client.ExecuteAsync(request).Result;
//if you have async method better to use
var response = await client.ExecuteAsync(request);
Data data = JsonConvert.DeserializeObject<Data>(response.Content);

How to call REST api result json having c# keywords

I am trying to access a simple REST Api, https://api.cryptonator.com/api/ticker/btc-usd
The result of the same is like this format:
{"ticker":{"base":"BTC","target":"USD","price":"9969.76308171","volume":"127575.47420967","change":"-197.36472278"},"timestamp":1517410741,"success":true,"error":""}
Now, when I am trying to get result from it, I find ticker objet of json null, timestamp and error objects are getting filled.
So, I suspect there might be the problem datamembers are not matching with json text. My Modeldto looks like this:
public class CurtoUsd
{
public ticker tick { get; set; }
public Single timestamp { get; set; }
public bool success { get; set; }
public string error { get; set; }
}
public class ticker
{
public string _base { get; set; }
public string target { get; set; }
public string price { get; set; }
public string volume { get; set; }
public string change { get; set; }
}
Please have a look, I was suppose to use base as variable but it is the keyword, so instead i used _base.
And I am using httpclient to in asp.net core 2.0 webapi and the code looks like this:
HttpClient client = new HttpClient();
if (client.BaseAddress == null)
{
client.BaseAddress = new Uri("https://api.cryptonator.com/");
}
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.GetAsync(baseUrl);
CurtoUsd usdrate = new CurtoUsd();
if (response.IsSuccessStatusCode)
{
usdrate = await response.Content.ReadAsJsonAsync<CurtoUsd>();
}
return CommonFunctions.ConvertDouble(usdrate.tick.price);
Detail
of function:
public static class HttpContentExtensions
{
public static async Task<T> ReadAsJsonAsync<T>(this HttpContent content)
{
string json = await content.ReadAsStringAsync();
T value = JsonConvert.DeserializeObject<T>(json);
return value;
}
}
May I know what's wrong I am doing? Is the point I have pointed out correct, is there any solution if it is so.
Please help.
You can use # in C# to use keywords as identifiers, e.g. foo.#base.#class.
So your DTO becomes:
public class Ticker
{
public string #base { get; set; } // Escape the `base` keyword with `#`
public string target { get; set; }
public string price { get; set; }
public string volume { get; set; }
public string change { get; set; }
}
Note that you should use PascalCase for type identifiers n C#/.NET (so class Ticker instead of class ticker), and for public members too.
Note that Newtonsoft.Json is actually case-insensitive for member names by default (unless you specifically configure it otherwise) so you can use PascalCase for the properties, this also stops them from being C# keywords too, and it will still work:
public class Ticker
{
public string Base { get; set; } // `Base` is not a keyword
public string Target { get; set; }
public string Price { get; set; }
public string Volume { get; set; }
public string Change { get; set; }
}

Deserialize Object into a class does not work

I am trying to set a class for a token using DeserializeObject from the json object i get back from my api. However when i run the below code it sets all the values to null or 0, not the result i am getting from the api.
cs code
var resultString = await result.Content.ReadAsStringAsync();
var post = JsonConvert.DeserializeObject<Token>(resultString);
class
public class Token : ContentPage
{
public int StaffID { get; set; }
public string TokenApi { get; set; }
public string StaffForename { get; set; }
public string StaffSurname { get; set; }
public string StaffEmail { get; set; }
public int PrimaryStaffRoleID { get; set; }
}
JSON response
"{\"code\":201,\"status\":\"Success\",\"message\":\"Object found\",\"data\":{\"StaffID\":14,\"StaffSurname\":\"Test\",\"StaffForename\":\"Test\",\"StaffEmail\":\"test#test.com\",\"PrimaryStaffRoleID\":5,\"TokenApi\":\"testToken\"}}"
Firstly the data which you are trying to map is inside another property in your json called Data and secondly your json does not have a property with name Token
The problem actually is you are not using the correct type that reflects your json, means you don't have correct c# type which would get mapped to json, you can generate correct types using json2charp.com , the correct classes for it are :
public class Data
{
public int StaffID { get; set; }
public string StaffSurname { get; set; }
public string StaffForename { get; set; }
public string StaffEmail { get; set; }
public int PrimaryStaffRoleID { get; set; }
public string TokenApi { get; set; }
}
public class RootObject
{
public int code { get; set; }
public string status { get; set; }
public string message { get; set; }
public Data data { get; set; }
}
Now deserializing using RootObject as type parameter would work perfectly fine like:
var resultString = await result.Content.ReadAsStringAsync();
var post = JsonConvert.DeserializeObject<RootObject>(resultString);
A more good option is to use QuickType.IO which would even generate code for you in c# or any other language that they are supporting.
If you analyze the JSON that you posted, the object that you're trying to Deserialize is inside the "data" property of your json.
I suggest you creating a class to represent the JsonResponse with a Data property. This will be your Token
You are retrieved a string that match this object
public string code {get;set;}
public string Success {get;set;} ...
And Token is matching data in json, so
var post = JsonConvert.DeserializeObject<Token>(resultString.data);
would be better.

Asp.NET HttpClient with custom JsonConverter

Hi I have the following code to get data from a REST service:
HttpResponseMessage response;
response = client.GetAsync("CatalogUpdate/" + sessionId).Result;
if (response.IsSuccessStatusCode)
{
catalogs = response.Content.ReadAsAsync<List<Models.CatalogInfo>>().Result;
}
My CatalogInfo class is:
public class CatalogInfo
{
public CatalogInfo(int id,string name,string date)
{
this.ID = id;
this.Name = name;
this.Date = date;
}
public int ID { get; set; }
public string Name { get; set; }
public string Date { get; set; }
}
And the jSON that Im getting from the REST service is:
{"error":false,"locations":[{"ID":"3","ABC":"XC","Description":"Rome","Status":"1"},{"ID":"4","CD1":"XH","Description":"Italy","Status":"1"}]}
I want to map the jSON to my CatalogInfo class, is there a way to do this?
The easiest option here is to use Json.NET and to create classes that represent the expected JSON, so for example:
class Location
{
public string ID { get; set; }
public string Description { get; set; }
}
class JSONResponse
{
[JsonProperty("error")]
public bool Error { get; set; }
[JsonProperty("locations")]
public Location[] Locations { get; set; }
}
We don't have to implement every property as Json.NET will just ignore what isn't there.
Then deserialize the response. In your case you're using HttpResonseMessage so something like this:
JSONResponse response = JsonConvert.DeserializeObject<JSONResponse>(
await response.Content.ReadAsStringAsync()
);
You can then use LINQ to convert the locations over to your object:
CatalogInfo[] catalog = response.Locations.Select(loc => new CatalogInfo(
loc.ID,
loc.Description,
String.Empty
)).ToArray();

converting from json to c# class object

I try to convert from json to c# class object, cause my final step will be put this all data into local db. I have no problem with taking this data like one big string, so the Url is good typed, but it's not my goal.
this is the json data, here we have two objects
[{"id":"1","category":"1","name":"good 1","prize":"12.3","prize2":"13.4","elements":"row,column,paper","secid":"2131","description":"nice","quality":"best","dateofcoming":"2013-12-20 18:08:50","date":"2013-12-20 00:00:00"},
{"id":"2","category":"2","name":"good","prize":"14.3","prize2":"15.4","elements":"up,down,left","secid":"2132","description":"nc","quality":"best","dateofcoming":"2013-12-20 18:10:55","date":"2013-12-20 00:00:00"}]
I try by this way which I found in the book:
private void getBookData()
{
// we creating the request details to the site which give us
// back the json data
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create("here is my adress");
request.Accept = "and header";
// starting the request
request.BeginGetResponse(callback_with_food_info, request);
}
private void callback_with_food_info(IAsyncResult ar)
{
HttpWebRequest request = (HttpWebRequest)ar.AsyncState;
// we get the response
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(ar);
DataContractJsonSerializer deserializer = new DataContractJsonSerializer(typeof(ListOfObjects));
Stream responseStream = response.GetResponseStream();
ListOfObjects listOfobj = (ListOfObjects)deserializer.ReadObject(responseStream);
String fsdfsdf = "how how how";
}
and in the row when we ReadObject
ListOfObjects listOfobj = (ListOfObjects)deserializer.ReadObject(responseStream);
I get exception "System.InvalidCastException", my List class look like this and it was created by http://json2csharp.com/
public class DetailsOfObject
{
public string id { get; set; }
public string category { get; set; }
public string name { get; set; }
public string prize { get; set; }
public string prize2 { get; set; }
public string elements { get; set; }
public string secid { get; set; }
public string description { get; set; }
public string quality { get; set; }
public string dateofcoming { get; set; }
public string date { get; set; }
}
public class ListOfObjects
{
public DetailsOfObject list {get; set;}
}
Any advice how to finally convert this json data
You need to add Data attributes to model
[DataContract]
public class DetailsOfObject
{
[DataMember]
public string id { get; set; }
and change deserialize line
List<DetailsOfObject> listOfobj = (List<DetailsOfObject>)deserializer.ReadObject(responseStream);

Categories

Resources