JSON. A reference deserializes to null - json

I am using Newtonsoft.json. I can't understand result of a deserialization. Bulletin.PageList is being filled ok. But Page of Question which is referencing to element of PageList is always null. In the JsonSerializerSettings I specified PreserveReferencesHandling.All but it didn't help. Could you help to resolve the problem of null of Page? Thank you
JSON structure:
"Bulletins": [
{
"$id": "46b5efa80fe644d7bd525e2c30f5df8a",
"$type": "Bulletin",
"JSONNETTYPE": "Bulletin",
"PagesList": [
{
"id": "4ed13d727cd144d1acf1e0c9bc273245",
"JSONNETTYPE": "PageView",
"Number": 1,
"Id": "1a2b8ed4249948e194b396c46a5d1eeb",
"UiId": "4ed13d727cd144d1acf1e0c9bc273245"
}
],
"AgendaQuestions": [
{
"$id": "eceb6fe6c74a40d59f0673b76bd6dbb3",
"$type": "QSimple",
"Page": {
"$ref": "46b5efa80fe644d7bd525e2c30f5df8a#PagesList.0"
}
}
]
}]
C# structure:
public class Bulletin
{
public Bulletin()
{
}
public string Dbid { get; set; }
public List<PageView> PagesList;
public List<Question> AgendaQuestions;
}
public abstract class Question
{
protected Question(int number, string customNumberLabel = null)
{
Number = number;
CustomNumberLabel = customNumberLabel;
}
public int Number { get; set; }
public string CustomNumberLabel { get; set; }
public PageView Page { get; set; }
}
public class PageView
{
public int Number { get; set; }
public string Id { get; set; }
public int BulletinNumber { get; set; }
public PageView()
{
}
}
var settings = new JsonSerializerSettings
{ PreserveReferencesHandling = PreserveReferencesHandling.All
}

I was using dojox.json.ref library. If I set __id for Page, references to elements of PagesList will become direct, not complex (like 46b5efa80fe644d7bd525e2c30f5df8a#PagesList.0), and Page is filled.

Related

Deserialize complex json in C#

I have this json and need to parse the nested details. using Newtonsoft.Json for Deserializing but cant really parse this complex json.
{
"name": "John",
"email": "john#gmail.com",
"data": [
{
"company_name": "instagram",
"company_email": "abc#email.com",
"org": {
"org_name": "john-insta",
"org_dob": "1/1/1990",
}
},
{
"company_name": "google",
"company_email": "abc1#email.com",
"org": {
"org_name": "john-google",
"org_dob": "1/1/1990",
}
},
]
The number of entries in "data" may actually be varying dynamically, how do I parse the entries for company_name, company_email, org_name,org_dob.
What is the problem you are having? This seems fairly simple JSON array. Setup your classes like this.
public class MyClass
{
public string name { get; set; }
public string email { get; set; }
public List<DataClass> data { get; set; }
}
public class DataClass
{
public string company_name { get; set; }
public string company_email { get; set; }
public Org org { get; set; }
//Any other and all possible properties...
}
public class Org
{
public string org_name { get; set; }
public string org_dob { get; set; }
}
Then it can be parsed using Newtonsoft or similar using.
var test = JsonConvert.DeserializeObject<MyClass>(json);
This method also has an overload where you can pass settings to ignore nulls.
var test = JsonConvert.DeserializeObject<MyClass>(json,
new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });

How to display JSON data in Xamarin.forms list view?

I am new to xamarin.forms, and i want to build an cross platform app that will display JSON data in the list view. This is my JSON data.
{
"fish_product": [
{
"fish_id": "1",
"fish_img": "",
"fish_name": "Indian Mackerel",
"fish_category": "Marine Fish",
"size": "Medium",
"price": "100"
},
{
"fish_id": "2",
"fish_img": "",
"fish_name": "Manthal Repti",
"fish_category": "Marine Fish",
"size": "Small",
"price": "200"
},
{
"fish_id": "4",
"fish_img": "",
"fish_name": "Baby Sole Fish",
"fish_category": "Marine Fish",
"size": "Small",
"price": "600"
}
]
}
I want to display "fish_name" in list view. please suggest any solution or any article or tutorial for this. thank you in advance.
I think you have to deserialize this JSON to an object like
public class FishProduct
{
public string fish_id { get; set; }
public string fish_img { get; set; }
public string fish_name { get; set; }
public string fish_category { get; set; }
public string size { get; set; }
public string price { get; set; }
}
public class RootObject
{
public ObservableCollection<FishProduct> fish_product { get; set; }
}
Then you have to use a ListView where you set your listview.ItemsSource = myList.fish_product
Then you have to create a DataTemplate using ViewCell
In this ViewCell you can have a Label when you SetBinding the fish_name field. In code something like
Label label = new Label();
label.SetBinding(Label.TextProperty, "fish_name");
I think you can take a look to ListView Documents
I think this may help you
Your MODEL
public class FishProduct
{
public string fish_id { get; set; }
public string fish_img { get; set; }
public string fish_name { get; set; }
public string fish_category { get; set; }
public string size { get; set; }
public string price { get; set; }
}
public class RootObject
{
public List<FishProduct> fish_product { get; set; }
}
Webservice call and JSON Deserialisation
public async Task GetData()
{
try
{
HttpClient client = new HttpClient();
var result = await client.GetAsync("http://yourJSON_Url");
result.EnsureSuccessStatusCode();
string json = await result.Content.ReadAsStringAsync();
List<FishProduct> res= JsonConvert.DeserializeObject<List<FishProduct>>(json);
}
catch (Exception ex)
{
throw;
}
}

How to use a POCO object to access an array of options in the appsettings.json file (ASP.NET 5)

I am using ASP.NET 5 and I want to use POCO classes to access my appsettings.json file. This file looks like this:
{
"Data": {
"ErpSystemConnection": {
"ConnectionString": "[myConnectionString]"
}
},
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Verbose",
"System": "Information",
"Microsoft": "Information"
}
},
"GoogleAnalytics": {
"Account": [
{
"Name": "AccountName",
"ServiceAccountEmailAddress": "someEmail#someaccount.iam.gserviceaccount.com",
"KeyFileName": "key1.p12",
"Password": "notasecret"
},
{
"Name": "AnotherAccount",
"ServiceAccountEmailAddress": "anotherEmailAccount#someotheraccount.iam.gserviceaccount.com",
"KeyFileName": "key2.p12",
"Password": "notasecret"
}
],
"KeyFilePath": "/googleApis/"
}
}
The 'GoogleAnalytics' key contains an array of accounts that I wish to be able to access in a collection either as a list or an array.
I created a POCO to represent this key that contains a corresponding collection of 'Account' objects:
public class GoogleAnalytics
{
public Account[] Account { get; set; } = new Account[1];
public string KeyFilePath { get; set; }
public GoogleAnalytics()
{
}
}
And the 'Account' object:
public class Account
{
private const string _applicationName = #"Storefront Analytics";
private X509Certificate2 _certificate;
private ServiceAccountCredential _credential;
private AnalyticsService _service;
#region |--Properties--|
public string Name { get; set; }
public string Password { get; set; }
public string ServiceAccountEmailAddress { get; set; }
public string KeyFileName { get; set; }
public string KeyFilePath { get; set; }
public string KeyFileFullPath
{
get
{
return $"{KeyFilePath}{KeyFileName}";
}
}
public X509Certificate2 Certificate
{
get
{
if(_certificate == null)
{
ConfigureInstance();
}
return _certificate;
}
set
{
_certificate = value;
}
}
public ServiceAccountCredential Credential
{
get
{
if (_credential == null)
{
ConfigureInstance();
}
return _credential;
}
set
{
_credential = value;
}
}
public AnalyticsService Service
{
get
{
if (_service == null)
{
ConfigureInstance();
}
return _service;
}
set
{
_service = value;
}
}
#endregion
#region |--Constructors--|
public Account()
{
}
public Account(string password, string keyFileName,
string keyFilePath,
string serviceAccountEmailAddress, string accountName)
{
//TODO: Validate parameters
Password = password;
KeyFileName = keyFileName;
KeyFilePath = keyFilePath;
ServiceAccountEmailAddress = serviceAccountEmailAddress;
Name = accountName;
}
#endregion
private void ConfigureInstance()
{
Certificate = new X509Certificate2(KeyFileFullPath, Password, X509KeyStorageFlags.Exportable);
Credential = new ServiceAccountCredential(new ServiceAccountCredential.Initializer(ServiceAccountEmailAddress)
{
Scopes = new[] { AnalyticsService.Scope.Analytics }
});
Service = new AnalyticsService(new BaseClientService.Initializer()
{
HttpClientInitializer = Credential,
ApplicationName = _applicationName
});
}
}
My Controller:
public class GoogleAnalyticsController : Controller
{
#region |--Properties--|
[FromServices]
private IGoogleAnalyticsRepository _repo { get; set; }
#endregion
public GoogleAnalyticsController(IOptions<GoogleAnalytics> options)
{
var temp = options.Value;
}
}
The 'KeyFilePath' property is properly set in the IOptions instance.
The problem I am having is that the Account array contains null references - none of the accounts are being instantiated. I wondering if I am doing this wrong, or the Options Model doesn't support this type of behavior at this time?
Update in response to Shaun Luttin's answer
I implemented the changes listing in Shaun Luttin's answer. There seems to have been an additional problem. For whatever reason, all of the Account instances' properties were null until I simplified the class as follows:
public class Account
{
public string Name { get; set; }
public string Password { get; set; }
public string ServiceAccountEmailAddress { get; set; }
public string KeyFileName { get; set; }
public string KeyFilePath { get; set; }
}
Short Answer
I wondering if I am doing this wrong, or the Options Model doesn't support this type of behavior at this time?
You are doing one thing wrong. The Options Model does support arrays. You need NOT to initialize your array property with an array of size [1].
public Account[] Account { get; set; } = new Account[1]; // wrong
public Account[] Account { get; set; } // right
Demo
Here is a sample, just for you, that you can find here on GitHub.
MyOptions.cs
namespace OptionsExample
{
public class MyObj
{
public string Name { get; set; }
}
public class MyOptions
{
public string Option1 { get; set; }
public string[] Option2 { get; set; }
public MyObj[] MyObj { get; set; }
}
}
Startup.cs
namespace OptionsExample
{
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.OptionsModel;
using System.Linq;
public class Startup
{
public IConfigurationRoot Config { get; set; }
public Startup(IHostingEnvironment env)
{
Config = new ConfigurationBuilder().AddJsonFile("myoptions.json").Build();
}
public void ConfigureServices(IServiceCollection services)
{
services.AddOptions();
services.Configure<MyOptions>(Config);
}
public void Configure(IApplicationBuilder app,
IOptions<MyOptions> opts)
{
app.Run(async (context) =>
{
var message = string.Join(",", opts.Value.MyObj.Select(a => a.Name));
await context.Response.WriteAsync(message);
});
}
}
}
myoptions.json
{
"option1": "option1val",
"option2": [
"option2val1",
"option2val2",
"option2val3"
],
"MyObj": [
{
"Name": "MyObj1"
},
{
"Name": "MyObj2"
}
]
}
project.json dependencies
"dependencies": {
"Microsoft.AspNet.Mvc": "6.0.0-rc1-final",
"Microsoft.AspNet.Server.Kestrel": "1.0.0-rc1-final",
"Microsoft.Extensions.Configuration.Json": "1.0.0-rc1-final"
}
Output

Converting to correctly formatted JSON

I've been tasked will calling an API, that needs to take a JSON payload as its request.. An example format of the JSON is as follows:
{
"method":"methodname",
"in":[
{
"account":"acme",
"context":"abc123"
},
"content",
{
"mSearchText":"chocolate",
"mItemDataIDs":[
"Entry:ID",
"Entry:EntryRef",
"Entry:CategoryID"
]
}
]
}
I am using JSON.NET (Newstonsoft) to construct my JSON from .net objects.
The issue I am facing is correctly constructing the "in" section..
It appears to be an array of objects, but only the second item has a title ("content",{.....})..
The closest I can get is:
{
"method": "methodname",
"in":[
{
"account": "PANDO",
"context": "sdfsd22342"
},
{
"mSearchText":"chocolate",
"mItemDataIDs":[
"Entry:ID",
"Entry:EntryRef",
"Entry:CategoryID"
]
}
]
}
Which is identical apart from "content", is missing:
My code so far is:
public class Payload
{
public string method { get; set; }
[JsonProperty("in")]
public List<object> Items { get; set; }
}
public class AccountDetails
{
public string account { get; set; }
public string context { get; set; }
}
[JsonObject(Title = "content")]
public class Content
{
public string mSearchText { get; set; }
public string[] mItemDataIDs { get; set; }
}
Payload payload = new Payload();
payload.method = "methodname";
payload.Items = new List<object>();
payload.Items.Add(new AccountDetails
{
account = "acme",
context = "abc123"
});
Content conent = new Content
{
mSearchText = "chocolate",
mItemDataIDs = new string[] { "Entry:ID", "Entry:EntryRef", "Entry:CategoryID" }
};
payload.Items.Add(conent);
string jsonObject = JsonConvert.SerializeObject(payload, Formatting.Indented);
Any suggestions on what I can do?

Deserializing JSON to flattened class

I found the same question here...
Deserializing nested JSON structure to a flattened class with Json.NET using annotations
...but without a proper answer. One of the best suggestion is to wrap the nested object in a new class but this approach introduces another issue: lego name. In my example the most logic name for this class is the same name that parent class and of course is not possible. My example is simple, I just want to eliminate the "language" property in the parent class. Can somebody help me to do it?
using Newtonsoft.Json;
public partial class NamedType
{
public string Name { get; set; }
}
public class Proficiency
{
public string Level { get; set; }
public string Name { get; set; }
}
public class Language
{
public int Id { get; set; }
public string Name { get; set; }
//public Language Language { get; set; } //Compiler error
//public Language Value { get; set; } //Not correct
//public NamedType Language { get; set; } //Compiler error
//public NamedType Value { get; set; } //Ugly, isn't?
public Proficiency Proficiency { get; set; }
}
List<Language> languageList = JsonConvert.DeserializeObject<List<Language>>(json);
Example of json:
{
"languages": [
{
"id": 1,
"language": { "name": "Spanish" },
"proficiency": {
"level": "native_or_bilingual",
"name": "Native or bilingual proficiency"
}
},
{
"id": 2,
"language": { "name": "English" },
"proficiency": {
"level": "full_professional",
"name": "Full professional proficiency"
}
},
{
"id": 3,
"language": { "name": "Japanese" },
"proficiency": {
"level": "elementary",
"name": "Elementary proficiency"
}
}
]
}
In cases where JSON property names conflict with c# naming conventions, you can use DataMember or JsonProperty annotations to substitute a different name during serialization.
For instance, the following works with both DataContractJsonSerializer and Json.NET:
[DataContract]
public class Language
{
[DataContract]
class NamedType
{
[DataMember]
public string name { get; set; }
}
[DataContract]
class ProficiencyType
{
[DataMember]
public string level { get; set; }
[DataMember]
public string name { get; set; }
}
[DataMember(Name="id")]
public int Id { get; set; }
[IgnoreDataMember] // Do not serialize this property
public string Name { get; set; }
[IgnoreDataMember]
public string ProficiencyLevel { get; set; }
[IgnoreDataMember]
public string ProficiencyName { get; set; }
[DataMember(Name="language")] // serialize this nested class property with name "language"
[JsonProperty(ObjectCreationHandling=ObjectCreationHandling.Replace)] // When deserializing, always create a fresh instance instead of reusing the proxy class.
NamedType LanguageName
{
get
{
return new NamedType { name = Name };
}
set
{
Name = (value == null ? null : value.name);
}
}
[DataMember(Name = "proficiency")]
[JsonProperty(ObjectCreationHandling = ObjectCreationHandling.Replace)]
ProficiencyType Proficiency
{
get
{
return new ProficiencyType { level = ProficiencyLevel, name = ProficiencyName };
}
set
{
ProficiencyLevel = (value == null ? null : value.level);
ProficiencyName = (value == null ? null : value.name);
}
}
}
If you find the opt-in nature of DataContract attributes to be a nuisance and prefer to use Json.NET-specific attributes, then the following is equivalent:
public class Language
{
class NamedType
{
public string name { get; set; }
}
class ProficiencyType
{
public string level { get; set; }
public string name { get; set; }
}
[JsonProperty(PropertyName = "id")]
public int Id { get; set; }
[JsonIgnore]
public string Name { get; set; }
[JsonIgnore]
public string ProficiencyLevel { get; set; }
[JsonIgnore]
public string ProficiencyName { get; set; }
[JsonProperty(PropertyName = "language", ObjectCreationHandling = ObjectCreationHandling.Replace)]
NamedType LanguageName
{
get
{
return new NamedType { name = Name };
}
set
{
Name = (value == null ? null : value.name);
}
}
[JsonProperty(PropertyName = "proficiency", ObjectCreationHandling = ObjectCreationHandling.Replace)]
ProficiencyType Proficiency
{
get
{
return new ProficiencyType { level = ProficiencyLevel, name = ProficiencyName };
}
set
{
ProficiencyLevel = (value == null ? null : value.level);
ProficiencyName = (value == null ? null : value.name);
}
}
}