Deserialize JSON having keys with CamelCase and snake_case naming in C# - 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.

Related

Convert JSON object to Model in .NET

I have this JSON object returned from API:
[
{
"batchId": 789,
"debtId": 1841,
"dateAdded": "2021-07-27T16:01:39.41",
"debtCategoryId": 2,
"agreementNumber": 78262155,
"clientNumber": 1068055,
"clientName": "Client Two"
},
{
"batchId": 866,
"debtId": 1918,
"dateAdded": "2021-08-25T14:47:18.13",
"debtCategoryId": 2,
"agreementNumber": 1000140792,
"clientNumber": 11213287,
"clientName": "Client One"
}
]
I'm trying to convert that to a C# object which has this structure:
public class DebtConfirmationResponse
{
public List<DebtConfirmation> DebtConfirmations { get; set; }
}
Where DebtConfirmation has these properties:
public class DebtConfirmation
{
public int BatchId { get; set; }
public int DebtId { get; set; }
public string DateAdded { get; set; }
public int DebtCategoryId { get; set; }
public string AgreementNumber { get; set; } = string.Empty;
public string ClientNumber { get; set; } = string.Empty;
public string ClientName { get; set; } = string.Empty;
}
The error I'm getting is:
the json value could not be converted to the name of the model path $
linenumber 0 bytepositioninline 1
Is there anything wrong with the way how the model is being setup?
I also tried converting to the same model with batch id only as a property and I got the same message.
You define AgreementNumber, ClientNumber as strings in your C# code, but this properties is numbers in json, so you have to define it as longs.
And the another point is that you don't need a wrapper around DebtConfirmation class. Deserealize your json into ICollection, IList or just List of DebtConfirmation objects.
I used the quicktype.io for retrieving C# classes from json example you provide. This is very helpful for those who doesn't want to manually generate the models for their JSON strings.
Here is the code sample.
The output is:
789
866
using System.Text.Json;
using System.Text.Json.Serialization;
string json = "[\n {\n \"batchId\": 789,\n \"debtId\": 1841,\n \"dateAdded\": \"2021-07-27T16:01:39.41\",\n \"debtCategoryId\": 2,\n \"agreementNumber\": 78262155,\n \"clientNumber\": 1068055,\n \"clientName\": \"Client Two\"\n },\n {\n \"batchId\": 866,\n \"debtId\": 1918,\n \"dateAdded\": \"2021-08-25T14:47:18.13\",\n \"debtCategoryId\": 2,\n \"agreementNumber\": 1000140792,\n \"clientNumber\": 11213287,\n \"clientName\": \"Client One\"\n }\n]";
var data = JsonSerializer.Deserialize<ICollection<DebtConfirmation>>(json);
foreach (DebtConfirmation current in data)
{
Console.WriteLine(current.BatchId);
}
public partial class DebtConfirmation
{
[JsonPropertyName("batchId")]
public long BatchId { get; set; }
[JsonPropertyName("debtId")]
public long DebtId { get; set; }
[JsonPropertyName("dateAdded")]
public DateTimeOffset DateAdded { get; set; }
[JsonPropertyName("debtCategoryId")]
public long DebtCategoryId { get; set; }
[JsonPropertyName("agreementNumber")]
public long AgreementNumber { get; set; }
[JsonPropertyName("clientNumber")]
public long ClientNumber { get; set; }
[JsonPropertyName("clientName")]
public string ClientName { get; set; }
}
You can use #GeorgyTarasov's answer. But it is definitely not the simplest option.
You can simply use JsonNamingPolicy.CamelCase.
Then you would simply do...
var options = new JsonSerializerOptions
{
DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,
};
var ret = JsonSerializer.Deserialize<DebtConfirmation>(payload, options);
If you are using AspNet Core, you can register the option here
services.AddControllers()
.AddJsonOptions(options =>
{
options.JsonSerializerOptions.DictionaryKeyPolicy = JsonNamingPolicy.CamelCase;
});

Convert JSON string to object C#

I have JSON string results as follows.
In this response Sometimes sizeKey and sizeName properties are returned as a string. But sometimes both properties are returns inside an array as follows
I am using following code to convert it to object
var assets = jObject["assets"].Children().ToList();
foreach (var item in assets)
{
decorationAssets.Add(item.ToObject<AEDecorationAssets>());
}
And my AEDecorationAssets class is as follows.
public class AEDecorationAssets
{
public string Id { get; set; }
public string Url { get; set; }
public string[] Colors { get; set; }
public string FontKey { get; set; }
public string SizeKey { get; set; }
public string ViewKey { get; set; }
public string FontName { get; set; }
public int Rotation { get; set; }
public string SizeName { get; set; }
public string TextValue { get; set; }
public string EntityType { get; set; }
public string LocationCode { get; set; }
public string LocationName { get; set; }
public string TextEffectKey { get; set; }
public string TextEffectName { get; set; }
public string DecorationMethod { get; set; }
public string NumDecorationColors { get; set; }
}
At the time when "sizeKey" is an array, the above code gives an error. How can I resolve this issue? Is there any JSON property we can use to resolve it?
One way you can do it is by making your SizeKey type an object (i.e. public object SizeKey { get; set; }), then you can switch/case on item.ToObject<AEDecorationAssets>().SizeKey.GetType() to figure out how to handle it (i.e. if String do this, if JArray do that), etc.
If a JSON type is sometime an array, and sometimes a string, you can't really map it simply to a .NET type, as there is none that supports this behavior.
So first you need a datatype that can store this, like and string[] or List<string>.
It could be that JsonConvert will solve this automatically, but otherwise you'll need to write a custom ContractResolver or JsonConverter. Here you can detect if the source property is a string or array. If it's an array, you can use the default deserialization. If it is a string, you need to convert it to an array with a single value.
Simply get json result for which you want to create c# object and then you can valid json response from https://jsonlint.com/ and then you can create c# object of any type json response which you want through http://json2csharp.com. And after get c# object of your json response you only need to deserialization of your json response to c# object which you have created. which will return you expected result.

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; }
}

Deserialize Json when name is dynamic

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);

get deserialize json objects into list c#

I'm getting json string from webapi like this
{"page":1,"total_results":33,"total_pages":2,"results":
[{"vote_count":8017,"id":603,"video":false,"vote_average":7.9,"title":"The Matrix","popularity":7.82272,"poster_path":"\/lZpWprJqbIFpEV5uoHfoK0KCnTW.jpg","original_language":"en","original_title":"The Matrix","genre_ids":[28,878],"backdrop_path":"\/7u3pxc0K1wx32IleAkLv78MKgrw.jpg","adult":false,"overview":"Set in the 22nd century, The Matrix tells the story of a computer hacker who joins a group of underground insurgents fighting the vast and powerful computers who now rule the earth.","release_date":"1999-03-30"},
{"vote_count":2750,"id":605,"video":false,"vote_average":6.4,"title":"The Matrix Revolutions","popularity":5.073697,"poster_path":"\/sKogjhfs5q3azmpW7DFKKAeLEG8.jpg","original_language":"en","original_title":"The Matrix Revolutions","genre_ids":[12,28,53,878],"backdrop_path":"\/pdVHUsb2eEz9ALNTr6wfRJe5xVa.jpg","adult":false,"overview":"The human city of Zion defends itself against the massive invasion of the machines as Neo fights to end the war at another front while also opposing the rogue Agent Smith.","release_date":"2003-11-05"},
{"vote_count":0,"id":411948,"video":false,"vote_average":0,"title":"Matrix","popularity":1.004394,"poster_path":"\/cseRq8R9RGN66SNUgcD7RJAxBI7.jpg","original_language":"en","original_title":"Matrix","genre_ids":[],"backdrop_path":null,"adult":false,"overview":"John Whitney, Sr. (April 8, 1917 – September 22, 1995) was an American animator, composer and inventor, widely considered to be one of the fathers of computer animation.","release_date":"1971-05-18"}]}
I only want to get title from above string into list.
Here's my code
public List<string> ExtractMoviesList(string movieTitle)
{
using (var client = new HttpClient())
{
// HTTP GET
var response = client.GetAsync(string.Format("{0}{1}", movies_Url, movieTitle)).Result;
using (HttpContent content = response.Content)
{
var json = content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<List<Movies>>(json.Result);
return result.Select(p=>p.Title).ToList();
}
}
}
There's something wrong with this line of code: var result = JsonConvert.DeserializeObject<List<Movies>>(json.Result); after this line executed the var result is getting just null.
Your problem is that you are trying to deserialize your JSON as a List<T>, but the root object in your JSON is not an array, it's an object. This is easy to see if you format and indent your JSON using, say, https://jsonformatter.curiousconcept.com/:
{
"page":1,
"total_results":33,
"total_pages":2,
"results":[
{
"title":"The Matrix",
// Other fields
},
// Other movies
]
}
The data model to which you are binding your JSON must reflect this outer container object for deserialization to succeed. Luckily http://json2csharp.com/ or Paste JSON as Classes will generate one for you:
public class Movie
{
public string title { get; set; }
public int vote_count { get; set; }
public int id { get; set; }
public bool video { get; set; }
public double vote_average { get; set; }
public double popularity { get; set; }
public string poster_path { get; set; }
public string original_language { get; set; }
public string original_title { get; set; }
public List<object> genre_ids { get; set; }
public string backdrop_path { get; set; }
public bool adult { get; set; }
public string overview { get; set; }
public string release_date { get; set; }
}
public class RootObject
{
public int page { get; set; }
public int total_results { get; set; }
public int total_pages { get; set; }
public List<Movie> results { get; set; }
}
Now you can do:
var result = JsonConvert.DeserializeObject<RootObject>(json.Result);
return result.results.Select(m => m.title).ToList();
Incidentally, if you don't want to create a data model just to extract the titles from this JSON, you can use Json.NET's LINQ to JSON functionality to load and query the JSON directly:
var result = JToken.Parse(json.Result);
return result.SelectTokens("results[*].title").Select(t => (string)t).ToList();
Here I am using SelectTokens() with the JsonPATH wildcard operator [*] to find all entries in the results array.
Working .Net fiddle showing both options.

Categories