Deserialize Json when name is dynamic - c#

I use this simple API, https://exchangeratesapi.io/ and I test with this uri: https://api.exchangeratesapi.io/history?start_at=2018-01-01&end_at=2018-03-01&symbols=SEK.
I want to deserialize the 'rates' part. Here is one response sample
And here is the code
public class ExchangeRate
{
[JsonProperty(PropertyName = "end_at", Order = 1)]
public DateTime EndAt { get; set; }
[JsonProperty(PropertyName = "start_at", Order = 2)]
public DateTime StartAt { get; set; }
[JsonProperty(PropertyName = "rates", Order = 3)]
public Dictionary<string, Rate> Rates { get; set; }
[JsonProperty(PropertyName = "base", Order = 4)]
public string Base { get; set; }
}
public class Rate
{
[JsonProperty]
public Dictionary<string, double> Fields{ get; set; }
}
or
public class Rate
{
[JsonProperty]
public string CurrencyName { get; set; }
[JsonProperty]
public double CurrencyRate { get; set; }
}
And I deserilize it like this
var result = Newtonsoft.Json.JsonConvert.DeserializeObject<ExchangeRateHistory>(response.Content);
My problem is that that Fields is null. Does anyone have any suggestion?

If your key/value pair are not fixed and data must be configurable then Newtonsoft.json has one feature that to be use here and that is [JsonExtensionData]. Read more
Extension data is now written when an object is serialized. Reading and writing extension data makes it possible to automatically round-trip all JSON without adding every property to the .NET type you’re deserializing to. Only declare the properties you’re interested in and let extension data do the rest.
In your case rates key have value as dynamic data so your Rate class will be
public class Rate
{
[JsonExtensionData]
public Dictionary<string, JToken> Fields { get; set; }
}
And then you can deserialize your response content as
var result = Newtonsoft.Json.JsonConvert.DeserializeObject<ExchangeRate>(response.Content);

Related

how to put anonymous json as class member and convert all to json in c#

I'm having a well-defined class for sending as JSON body in an HTTP request.
public class EventData
{
public string deviceJobId { get; set; }
public int eventID { get; set; }
public long time_ms { get; set; }
/// similar fields
}
Now I have to add one more field called HealthInfo. The value of this new HealthInfo is a nested JSON read from some file.
The fields of this JSON file change from time to time, and there is no guarantee that some fields will always be present.
I don't want to read/modify any value of that and just need to publish this EventData as a json as part of an HTTP request.
Then how to add HealthInfo correctly?
I tried to put HealthInfo as string and object is getting double serialized.
you have to convert to JObject before you add new json string
JObject jo = JObject.FromObject(eventData);
jo["HealthInfo"] = jsonStringHealthInfo;
//or it could be (your question needs some details)
jo["HealthInfo"]=JObject.Parse(jsonStringHealthInfo);
StringContent content = new StringContent(jo.ToString(), Encoding.UTF8, "application/json");
var response = await client.PostAsync(api, content))
If you know all of the possible properties inside HealthInfo then you can create new class HealthInfo with nullable properties.
public class HealthInfo
{
public string? SomeData { get; set; }
public int? SomeOtherData { get; set; }
}
and then add nullable HealthInfo in your main class:
public class EventData
{
public string deviceJobId { get; set; }
public int eventID { get; set; }
public long time_ms { get; set; }
public HealthInfo? HealthInfo { get; set; }
/// similar fields
}
However if you're not sure what kind of data you're gonna get and want to avoid double serialization, just pass HealthInfo as object:
public class EventData
{
public string deviceJobId { get; set; }
public int eventID { get; set; }
public long time_ms { get; set; }
public object? HealthInfo { get; set; }
/// similar fields
}
You can use of C# reflection. (TypeBuilder.DefineProperty Method)
In fact you must add prop to the class in run time.
see full information at
https://learn.microsoft.com/

Deserialize JSON having keys with CamelCase and snake_case naming in C#

I am receiving a json file via api, that json file will be converted into a class that I cant touch and has around 400 properties. the json is using for the key names CamelCase and in the same json some keys are in the format of snake_case.
I am currently using System.Text.Json but open to change to Newtonsoft.json is needed.
I tried to create a JsonSnakeCaseNamingPolicy class (only converting the property names to snake_case) and used in the JsonSerializerOptions like this:
var deserializeOptions = new JsonSerializerOptions()
{
PropertyNameCaseInsensitive = true,
PropertyNamingPolicy = new JsonSnakeCaseNamingPolicy()
};
var flexImport = JsonSerializer.Deserialize<List<FlexImport>>(input.MappedObjectJson, deserializeOptions);
But then the properties in CamelCase don't get populated. Any idea on how to achieve this situation?
This the json sample:
[{\"BatchId\":123,\"Title_Id\":123,\"CurrentNumber\":\"aa705128\",\"address\":\"122 BLACKSGATE EN\",\"curr_interest_rate\":4},{\"BatchId\":2,\"Title_Id\":1,\"CurrentNumber\":\"27705128\",\"address\":\"90 ARMA DR\",\"curr_interest_rate\":5},{\"BatchId\":2,\"Title_Id\":2,\"CurrentNumber\":\"30877674\",\"address\":\"6485 N SIN CIR\",\"curr_interest_rate\":4}]"
And here is part of the destination class:
public class FlexImport
{
public long BatchId { get; set; }
public long TitleId { get; set; }
public string CurrentNumber { get; set; }
public string Address { get; set; }
public decimal? CurrInterestRate { get; set; }
}
Use JSON attributes
public class FlexImport
{
public long BatchId { get; set; }
[JsonPropertyName("Title_Id")]
public long TitleId { get; set; }
public string CurrentNumber { get; set; }
[JsonPropertyName("address")]
public string Address { get; set; }
[JsonPropertyName("curr_interest_rate")]
public decimal? CurrInterestRate { get; set; }
}
Etc. Adjust as needed.

Consume Data From this endpoint

I am getting tdata from a certain endpoint and the problem id on serialization to my classes. I want to cast the bellow data to my class but cant get how the class should be structured. Check out the data .....
{
"-LYG_AI_oGYjNBrzMlKF": {
"chatDispayText": "",
"chatId": "-LYG_AI_oGYjNBrzMlKF",
"chatName": "",
"chattype": "single",
"imageUrl": "https://wallpaper.wiki/wp-content/uploads/2017/04/wallpaper.wiki-Amazing-celebrities-hd-wallpaper-PIC-WPD004734.jpg",
"lastMessageSent": "aiye",
"lastMessageSentTime": 1549704416263,
"synched": false,
"users": {
"-LYG_AIZ5MvTbjR7DACe": "Uicpm3L15TX0c15pKCI6KUEARyB3",
"-LYG_AI_oGYjNBrzMlKE": "Xsr0z9lsqNOEytX61lJvaGz1A8F2"
}
}
}
If the data you get out the endpoint has a dynamic structure, you can make use of a key-vale pair collection or a dictionary. For instance:
JObject jObject = JObject.Parse(Data); // This would already give you a key-value pair collection
Dictionary<String,Object> collection = new Dictionary<String, Object>();
foreach(var obj in jObject){
collection.Add(obj.Key, obj.Value);
}
However, this isn't a strongly typed approach which means that it is not effective in the majority of scenarios. A better solution when dealing with endpoints would be to define a class with fixed schema, actually something you need in your code, and then map the class to the object yielded by the endpoint using a metadata struct. For example:
public class ChatInfoModel
{
[JsonProperty(Metadata.ChatId)]
public long ChatId { get; set; }
[JsonProperty(Metadata.ChatId, Required = Required.AllowNull)]
public String Message { get; set; }
}
public struct Metadata
{
public const String ChatId = "userChatId";
public const String Message = "messageTxt";
}
And then
var deserializedObject = JsonConvert.DeserializeObject<ChatInfoModel>(data);
However, if your class has the exact same naming convention (but should not necessarily follow the camelCase naming convention) for its properties as in the serialized data, the JsonProperty attribute would not be needed.
You can also deserialize the object without using JsonProperty attribute manually using the first approach, and it is actually advantageous in certain scenarios where your schema comes from a configuration file rather than a struct.
Take inspiration from the Structure below:
public class Rootobject
{
public LYG_AI_Ogyjnbrzmlkf LYG_AI_oGYjNBrzMlKF { get; set; }
}
public class LYG_AI_Ogyjnbrzmlkf
{
public string chatDispayText { get; set; }
public string chatId { get; set; }
public string chatName { get; set; }
public string chattype { get; set; }
public string imageUrl { get; set; }
public string lastMessageSent { get; set; }
public long lastMessageSentTime { get; set; }
public bool synched { get; set; }
public Users users { get; set; }
}
public class Users
{
public string LYG_AIZ5MvTbjR7DACe { get; set; }
public string LYG_AI_oGYjNBrzMlKE { get; set; }
}

JSON.Net Deserialization of non-generic Root Objects

I'm currently working on a project where I make a request to the Riot Games API, parse the JSON, and do some stuff with it. I have the request working, and I know I'm getting valid JSON. My issue is using JSON.Net to deserialize the JSON.
The JSON is of the following structure:
{
"xarcies": {
"id": 31933985,
"name": "Farces",
"profileIconId": 588,
"revisionDate": 1450249383000,
"summonerLevel": 30
}
}
I want to load this data into the following class
[JsonObject(MemberSerialization.OptIn)]
class Summoner
{
[JsonProperty("id")]
public long id {get;set;}
[JsonProperty("name")]
public string name { get; set; }
[JsonProperty("profileIconId")]
public int profileIconId { get; set; }
[JsonProperty("revisionDate")]
public long revisionDate { get; set; }
[JsonProperty("summonerLevel")]
public long summonerLevel { get; set; }
}
The issue I'm having is that because I'm given a "xarcies" object that contains the information I need, I'm not sure how to go about designing a class that can accept the JSON data. I've seen some examples that use a RootObject class to take the object and that class has a subclass that all the pairs are put into, but I can't seem to get it to work. Every time I run it the attributes for the object end up being NULL.
You can deserialize your JSON as a Dictionary<string, Summoner>:
var root = JsonConvert.DeserializeObject<Dictionary<string, Summoner>>(jsonString);
The dictionary will be keyed by the user name, in this case "xarcies". See Deserialize a Dictionary.
I just used json2csharp to create the following class (its types look a bit different then yours):
public class UserData
{
public int id { get; set; }
public string name { get; set; }
public int profileIconId { get; set; }
public long revisionDate { get; set; }
public int summonerLevel { get; set; }
}
public class RootObject
{
public KeyValuePair<string, UserData> value { get; set; }
}

Deserialize JSON with variable name arrays

I am getting JSON that is being returned from a REST web service for survey responses. It has arrays for the name portion of some of the name value pairs. Additionally the names will be variable depending on the type of questions asked. I'm using JSON.net and trying to deserialize the returned value into some type of object tree that I can walk but can't figure out what structure to use to have it filled in.
I tested the following snippet in LinqPad and fields is always empty. Is there someway to easily read in the variable data or do I have to parse it in code?
void Main() {
string json = #"{
'result_ok':true,
'total_count':'51',
'data':[{
'id':'1',
'status':'Deleted',
'datesubmitted':'2015-01-12 10:43:47',
'[question(3)]':'Red',
'[question(4)]':'Blue',
'[question(18)]':12,
'[variable(\'STANDARD_IP\')]':'127.0.0.1',
'[variable(\'STANDARD_GEOCOUNTRY\')]':'United States'
}]
}";
var responses = JsonConvert.DeserializeObject<RootObject>(json);
responses.Dump();
}
public class RootObject {
public bool result_ok { get; set; }
public string total_count { get; set; }
public List<Response> data { get; set; }
}
public class Response {
public string id { get; set; }
public string status { get; set; }
public string datesubmitted { get; set; }
public List<object> fields = new List<object>();
}
Change the fields property in your Response class to be a Dictionary<string, object>, then mark it with a [JsonExtensionData] attribute like this:
public class Response
{
public string id { get; set; }
public string status { get; set; }
public string datesubmitted { get; set; }
[JsonExtensionData]
public Dictionary<string, object> fields { get; set; }
}
All of the fields with the strange property names will then be placed into the dictionary where you can access them as normal. No extra code is required.
Here is a demo: https://dotnetfiddle.net/1rQUXT

Categories