I am retrieving some JSON from an external API that I have no control over and need to deserialise that into an object where some of the fields are nested into a property of the main object so a straight deserialise won't work.
The closest question I've found to my issue is:
Json .Net serialize flat object into a complex object (change objects structure on serialization/deserialization)
I couldn't really apply this to my problem though as i'm fairly new to using JSON.NET and still trying to understand how it works.
A small sample to demonstrate of the json back from the API:
{
FirstName: "John",
LastName: "Smith",
PassportNo: "xxxxx",
NiNo: "xxxxx",
}
The class(es) I want to deserialise into:
internal sealed class Person
{
[JsonProperty(PropertyName = "FirstName")]
public string FirstName { get; set; }
[JsonProperty(PropertyName = "LastName")]
public string LastName { get; set; }
public PrivateData PrivateData { get; set; }
}
internal sealed class PrivateData
{
[JsonProperty(PropertyName = "PassportNo")]
public string PassportNo { get; set; }
[JsonProperty(PropertyName = "NiNo")]
public string NationalInsuranceNumber { get; set; }
}
I wasn't sure how to go about implementing a custom contract resolver / JSON converter to attain the required results so any guidance would be appreciated.
You cannot use the default JsonConvert class of JSON.Net because it's not able to convert a flat json structure in a complex class. If I were in you I'll parse the json as a Dictionary<string, string> and then create your person class.
Something like this:
Dictionary<string, string> values = JsonConvert.DeserializeObject<Dictionary<string, string>>(json);
var person = new Person {
FirstName = values["FirstName"] ,
LastName = values["LastName "],
PrivateData = new PrivateData {
PassportNo = values["PassportNo"],
NationalInsuranceNumber = values["NiNo"]
}
};
Related
I need to serialize a deeply nested RealmObject to JSON for posting to a web api, using Xamarin with C#.
The reason for this is because I don't want the RealmObject properties to carry over, so really I'm looking for a POCO representation that I can serialize to JSON. I can't find any helper method in Realm for Xamarin to do this, so I'm guessing I need to roll my own.
I am considering a few options and was hoping for some feedback:
Use a JSON.NET Custom ContractResolver.
Including a ToObject method on the RealmObject that returns a dynamic type which I can then serialize using JsonConvert.SerializeObject
Using JsonTextWriter to iterate over the object and manually create the corresponding json.
At the moment I'm looking at option 2, as it's very straight forward e.g.
public class Person:RealmObject {
public string FirstName {get;set;}
public string LastName {get;set;}
public IList<Dog> Dogs {get;set;}
public dynamic ToObject(){
return new {FirstName,LastName, Dogs = Dogs.Select(x => x.ToObject())};
}
}
public class Dog {
public string Name;
public dynamic ToObject(){
return new {Name};
}
}
var person = new Person(){...}
var json = JsonConvert.SerializeObject(person.ToObject());
var content = new StringContent(json);
var response = await client.PostAsync(url, content);
Any thoughts?
If you don't mind applying a few attributes, a cleaner (in my mind) solution would be to use the JsonObject attribute with MemberSerialization.OptIn argument:
[JsonObject(MemberSerialization.OptIn)] // Only properties marked [JsonProperty] will be serialized
public class Person : RealmObject
{
[JsonProperty]
public string FirstName { get; set; }
[JsonProperty]
public string LastName { get; set; }
[JsonProperty]
public IList<Dog> Dogs { get; set; }
}
for simplicity I made very simple structures.
Incoming JSON:
jsonInput = "{ 'FNAME': 'John'; 'LNAME': 'Doe', 'CITY': 'Vancuver'}";
I need to integrate with my strongly typed object of class Person:
class Person
{
public string FNAME { get; set; }
public string LNAME { get; set; }
public string CITY { get; set; }
public string COUNTRY { get; set; }
}
Person object gets created first
(in real life from DB, but here I will just hard-code it):
var person = new Person { CITY = 'Toronto', COUNTRY = 'Canada'};
How to integrate (merge) jsonInput into person to have complete Person object. JSON data is supposed to override Person object only for matched properties
So, I de-serialize JSON jsonInput first into dynamic object
var obj = JsonConvert.DeserializeObject(jsonInput);
So, now I have partially populated obj object (that is of type JObject) and partially populated person object (of type Person).
How, in a single command I can merge them into person object.
Or maybe there is another way to deserialize jsonInput directly into person ??
The result should be:
person.FNAME = 'John'
person.LNAME = 'Doe'
person.CITY = 'Vancuver'
person.COUNTRY = 'CANADA'
What I want to avoid is looping through properties.
Thanks for any advice.
Use PopulateObject Method
JsonConvert.PopulateObject(jsonInput,person);
assuming you recive json as a parameter ...
jsonInput = "{
'PERSON' : {
'FNAME': 'John';
'LNAME': 'Doe',
'CITY': 'Vancuver'
}
}";
Public class Person{
public Person(string json,string city,string country){
JObject jObject = JObject.Parse(json);
JToken jPerson = jObject["PERSON"];
FNAME= (string) jPerson ["FNAME"];
LNAME= (string) jPerson ["LNAME"];
COUNTRY = country:
CITY= ((string) jPerson ["CITY"] == string.Empty)?city:(string) jPerson ["CITY"]; //IF CITY PROPERTY EMPTY USE CITY ELSE USE JSON PROPERTY
}
public string FNAME{ get; set; }
public string LNAME{ get; set; }
public string CITY{ get; set; }
public string COUNTRY{ get; set; }
}
not tested but hope that helps
I am having a problem deserializing some JSON string back into .net objects. I have a container class which contains some information from external and there is a field call ClassType which defined what type of information is that and the actual content is in another property, which currently can be anything, so we define that as an Object type.
Following are the .net class definition which helps to understand the issue.
class ClassOne
{
public string Name { get; set; }
public int Age { get; set; }
}
class ClassTwo
{
public string AddressLine { get; set; }
public string AddressLine2 { get; set; }
}
class ClassThree
{
public string Country { get; set; }
public string Passport { get; set; }
}
class ContainerClass
{
public string ClassType { get; set; }
public object ClassContent { get; set; }
}
When getting the information from external in a JSON format it will be something like:
{"ClassType":"Class1","ClassContent":{"Name":"James","Age":2}}
I am using Newtonsoft JSON.net library to deserialize the JSON string. It seems like that the default deserialize function will just deserialize that into an Newtonsoft.Json.Linq.JContainer. I just wondering how can I write some Converter to deserialize the ClassContent based on the ClassType definition. Any code sample will be highly appreciated.
I would go dynamic way, like:
string json = #"{""ClassType"":""Class1"",""ClassContent"":{""Name"":""James"",""Age"":2}}";
dynamic jObj = JObject.Parse(json);
if (jObj.ClassType == "Class1")
{
Console.WriteLine("{0} {1}", jObj.ClassContent.Name, jObj.ClassContent.Age);
}
Since returning an object (ClassContent) doesn't mean much, and you have to cast it to a concrete class somehow (using some if's or switch).
Sample:
var container = JsonConvert.DeserializeObject<ContainerClass>(json);
JContainer content = (JContainer)container.ClassContent;
switch(container.ClassType)
{
case "Class1": return container.ToObject(typeof(ClassOne));
..
}
use dynamic and call .ToObject(Type type)
dynamic root = JObject.Parse(json)
return root["ClassContent"].ToObject(Type.GetType(root["ClassType"]))
Try the following
var jsonObject = JObject.Parse(jsonString);
var result = jsonObject.ToObject(Type.GetType("namespace.className"));
Let's say I have this object:
[JsonObject]
public class User
{
[JsonProperty(PropertyName = "id")]
public string Id { get; set; }
[JsonProperty(PropertyName = "name")]
public string Name { get; set; }
[JsonProperty(PropertyName = "birthday")]
public DateTime Birthday { get; set; }
}
This will produce JSON like this:
{
"id":null,
"name":"Bob",
"birthday":"/Date(374479200000-0600)/"
}
I'm looking for a way to add the classname around all this, for example:
{
"user":{
"id":null,
"name":"Bob",
"birthday":"/Date(374479200000-0600)/"
}
}
Does JSON.NET have a way to do this? Thanks!
Edit
My reason for doing this was to connect a .NET client to a Rails web service. Rails puts a model's attributes under a namespace, so I was looking for a way for .NET to conform to this.
However, after reading a bit about Backbone.js, it looks like a possible alternative would be to disable this behavior in Rails:
If you're working with a Rails backend, you'll notice that Rails'
default to_json implementation includes a model's attributes under a
namespace. To disable this behavior for seamless Backbone integration,
set:
ActiveRecord::Base.include_root_in_json = false
If you want to do this just for the root object, I think the simplest way is just to enclose the object in a way that it gets serialized the way you want:
static object AddTypeName(object o)
{
return new Dictionary<string, object>
{
{ o.GetType().Name.ToLowerInvariant(), o }
};
}
I achieved this personally using JavaScriptSerializer.Serialize(Object):
JavaScriptSerializer javaScriptSerializer = new JavascriptSerializer();
javaScriptSerializer.Serialize( new { user = userObject } );
That should automatically deserialize the following class:
class User
{
string id;
int age;
}
into this:
{
user : {
id = '12321345',
age = 32
}
}
I'm relatively new to working with C# and JSON data and am seeking guidance. I'm using C# 3.0, with .NET3.5SP1, and JSON.NET 3.5r6.
I have a defined C# class that I need to populate from a JSON structure. However, not every JSON structure for an entry that is retrieved from the web service contains all possible attributes that are defined within the C# class.
I've been being doing what seems to be the wrong, hard way and just picking out each value one by one from the JObject and transforming the string into the desired class property.
JsonSerializer serializer = new JsonSerializer();
var o = (JObject)serializer.Deserialize(myjsondata);
MyAccount.EmployeeID = (string)o["employeeid"][0];
What is the best way to deserialize a JSON structure into the C# class and handling possible missing data from the JSON source?
My class is defined as:
public class MyAccount
{
[JsonProperty(PropertyName = "username")]
public string UserID { get; set; }
[JsonProperty(PropertyName = "givenname")]
public string GivenName { get; set; }
[JsonProperty(PropertyName = "sn")]
public string Surname { get; set; }
[JsonProperty(PropertyName = "passwordexpired")]
public DateTime PasswordExpire { get; set; }
[JsonProperty(PropertyName = "primaryaffiliation")]
public string PrimaryAffiliation { get; set; }
[JsonProperty(PropertyName = "affiliation")]
public string[] Affiliation { get; set; }
[JsonProperty(PropertyName = "affiliationstatus")]
public string AffiliationStatus { get; set; }
[JsonProperty(PropertyName = "affiliationmodifytimestamp")]
public DateTime AffiliationLastModified { get; set; }
[JsonProperty(PropertyName = "employeeid")]
public string EmployeeID { get; set; }
[JsonProperty(PropertyName = "accountstatus")]
public string AccountStatus { get; set; }
[JsonProperty(PropertyName = "accountstatusexpiration")]
public DateTime AccountStatusExpiration { get; set; }
[JsonProperty(PropertyName = "accountstatusexpmaxdate")]
public DateTime AccountStatusExpirationMaxDate { get; set; }
[JsonProperty(PropertyName = "accountstatusmodifytimestamp")]
public DateTime AccountStatusModified { get; set; }
[JsonProperty(PropertyName = "accountstatusexpnotice")]
public string AccountStatusExpNotice { get; set; }
[JsonProperty(PropertyName = "accountstatusmodifiedby")]
public Dictionary<DateTime, string> AccountStatusModifiedBy { get; set; }
[JsonProperty(PropertyName = "entrycreatedate")]
public DateTime EntryCreatedate { get; set; }
[JsonProperty(PropertyName = "entrydeactivationdate")]
public DateTime EntryDeactivationDate { get; set; }
}
And a sample of the JSON to parse is:
{
"givenname": [
"Robert"
],
"passwordexpired": "20091031041550Z",
"accountstatus": [
"active"
],
"accountstatusexpiration": [
"20100612000000Z"
],
"accountstatusexpmaxdate": [
"20110410000000Z"
],
"accountstatusmodifiedby": {
"20100214173242Z": "tdecker",
"20100304003242Z": "jsmith",
"20100324103242Z": "jsmith",
"20100325000005Z": "rjones",
"20100326210634Z": "jsmith",
"20100326211130Z": "jsmith"
},
"accountstatusmodifytimestamp": [
"20100312001213Z"
],
"affiliation": [
"Employee",
"Contractor",
"Staff"
],
"affiliationmodifytimestamp": [
"20100312001213Z"
],
"affiliationstatus": [
"detached"
],
"entrycreatedate": [
"20000922072747Z"
],
"username": [
"rjohnson"
],
"primaryaffiliation": [
"Staff"
],
"employeeid": [
"999777666"
],
"sn": [
"Johnson"
]
}
Use
var rootObject = JsonConvert.DeserializeObject<RootObject>(string json);
Create your classes on JSON 2 C#
Json.NET documentation: Serializing and Deserializing JSON with Json.NET
Have you tried using the generic DeserializeObject method?
JsonConvert.DeserializeObject<MyAccount>(myjsondata);
Any missing fields in the JSON data should simply be left NULL.
UPDATE:
If the JSON string is an array, try this:
var jarray = JsonConvert.DeserializeObject<List<MyAccount>>(myjsondata);
jarray should then be a List<MyAccount>.
ANOTHER UPDATE:
The exception you're getting isn't consistent with an array of objects- I think the serializer is having problems with your Dictionary-typed accountstatusmodifiedby property.
Try excluding the accountstatusmodifiedby property from the serialization and see if that helps. If it does, you may need to represent that property differently.
Documentation: Serializing and Deserializing JSON with Json.NET
You can use:
JsonConvert.PopulateObject(json, obj);
here: json is the json string,obj is the target object. See: example
Note: PopulateObject() will not erase obj's list data, after Populate(), obj's list member will contains its original data and data from json string
Building off of bbant's answer, this is my complete solution for deserializing JSON from a remote URL.
using Newtonsoft.Json;
using System.Net.Http;
namespace Base
{
public class ApiConsumer<T>
{
public T data;
private string url;
public CalendarApiConsumer(string url)
{
this.url = url;
this.data = getItems();
}
private T getItems()
{
T result = default(T);
HttpClient client = new HttpClient();
// This allows for debugging possible JSON issues
var settings = new JsonSerializerSettings
{
Error = (sender, args) =>
{
if (System.Diagnostics.Debugger.IsAttached)
{
System.Diagnostics.Debugger.Break();
}
}
};
using (HttpResponseMessage response = client.GetAsync(this.url).Result)
{
if (response.IsSuccessStatusCode)
{
result = JsonConvert.DeserializeObject<T>(response.Content.ReadAsStringAsync().Result, settings);
}
}
return result;
}
}
}
Usage would be like:
ApiConsumer<FeedResult> feed = new ApiConsumer<FeedResult>("http://example.info/feeds/feeds.aspx?alt=json-in-script");
Where FeedResult is the class generated using the Xamasoft JSON Class Generator
Here is a screenshot of the settings I used, allowing for weird property names which the web version could not account for.
I found my I had built my object incorrectly. I used http://json2csharp.com/ to generate me my object class from the JSON. Once I had the correct Oject I was able to cast without issue. Norbit, Noob mistake. Thought I'd add it in case you have the same issue.
You can try checking some of the class generators online for further information. However, I believe some of the answers have been useful. Here's my approach that may be useful.
The following code was made with a dynamic method in mind.
dynObj = (JArray) JsonConvert.DeserializeObject(nvm);
foreach(JObject item in dynObj) {
foreach(JObject trend in item["trends"]) {
Console.WriteLine("{0}-{1}-{2}", trend["query"], trend["name"], trend["url"]);
}
}
This code basically allows you to access members contained in the Json string. Just a different way without the need of the classes. query, trend and url are the objects contained in the Json string.
You can also use this website. Don't trust the classes a 100% but you get the idea.
Assuming your sample data is correct, your givenname, and other entries wrapped in brackets are arrays in JS... you'll want to use List for those data types. and List for say accountstatusexpmaxdate... I think you example has the dates incorrectly formatted though, so uncertain as to what else is incorrect in your example.
This is an old post, but wanted to make note of the issues.