I already looked at a lot of other questions with the same problem but never found a definitive solution that actually works for me. I tried using the JsonExtensionData Attribute, that doesn't work though since I can't convert my other data class to an object and it throws the Invalid extension data attribute on 'NAMESPACE'. Member 'Sols' type must implement IDictionary<string, JToken>. error.
My current data model class looks like this
public partial class Mars
{
public Dictionary<string, Sol> Sols { get; set; }
[JsonProperty("sol_keys")]
public List<long> SolKeys { get; set; }
}
public partial class Sol
{
[JsonProperty("AT")]
public At At { get; set; }
[JsonProperty("First_UTC")]
public DateTimeOffset FirstUtc { get; set; }
[JsonProperty("Last_UTC")]
public DateTimeOffset LastUtc { get; set; }
[JsonProperty("Season")]
public string Season { get; set; }
}
public partial class At
{
[JsonProperty("av")]
public double Av { get; set; }
[JsonProperty("ct")]
public long Ct { get; set; }
[JsonProperty("mn")]
public double Mn { get; set; }
[JsonProperty("mx")]
public double Mx { get; set; }
}
The json data looks like this
{
"651":
{
"AT":
{
"av": -61.957,
"ct": 302204,
"mn": -96.733,
"mx": -15.877
},
"First_UTC": "2020-09-25T02:42:14Z",
"Last_UTC": "2020-09-26T03:21:49Z",
"Season": "summer"
},
"652": {
"AT": {
"av": -65.002,
"ct": 278608,
"mn": -96.111,
"mx": -15.653
},
"First_UTC": "2020-09-26T03:21:50Z",
"Last_UTC": "2020-09-27T04:01:24Z",
"Season": "summer"
},
"sol_keys": [
"646",
"647",
"648",
"649",
"650",
"651",
"652"
]
}
I can't really modify the json data since I get it from an api.
I basically just want to select one of the numbers and then get the Sol data of that object.
Any help would be appreciated.
The JSON doesn't fit well with the C# type system. However, you can still use Json.Net to parse it. You just need to introduce some extra steps.
First step is to parse the JSON to a JObject:
var jObject = JsonConvert.DeserializeObject<JObject>(json);
Then you can extract the sol_keys:
var solKeys = jObject.GetValue("sol_keys").ToObject<long[]>();
Now it becomes a bit tricky. If you remove the sol_keys from the JSON (in this case the parsed JSON) it has the structure of a dictionary of Sol objects that you are able to parse:
jObject.Remove("sol_keys");
var mars = jObject.ToObject<Dictionary<long, Sol>>();
Now you have both solKeys and mars parsed from the JSON. Furthermore the solKeys and the keys in the dictionary share the same type (long).
Related
I am working with a huge JSON file, where is just needed to extract some fields inside it. I've been searching some ways to deserialize, but don't want to create the whole Class and Object in C# with all the fields inside the JSON, this would be a lot of useless memory.
I can get the JSON file using a Webclient:
using (WebClient wc = new WebClient())
{
jsonWeb = wc.DownloadString("http://link_to_get_JSON");
}
//Deserialize into a JObject
JObject obj = JObject.Parse(jsonWeb);
//Tried to access the info with
var val = obj.PropTwo;
var solution = obj.Descendants().OfType<JProperty>().Where(p => p.Name == "solverSolution").Select(x => x.Value.ToString()).ToArray();
I really could not find a way to get the wanted fields inside the JObject.
Inside the JSON, the only information is needed is the solverSolution:{} below:
{
"content":
[
{
"id":"f4d7e7f5-86ab-4155-8336-ca5f552cb3b4",
"name":"m1",
"description":"m1",
"maxHeight":2000.0,
"layers":6,
"pallet":{},
"product":{},
"solverSolution":
{
"id":"106ef605-d95e-4c74-851b-63310fbcbc7d",
"name":"solver",
"maxHeight":2000.0,
"layers":6,
"solution":[
{
"X1":0,
"Y1":0,
"Z1":0,
"X2":296,
"Y2":246,
"Z2":220
},
...
"default":false
},
"customSolutions":[0]
},
{},
...
],
"pageable":{},
"totalPages":1,
"last":true,
"totalElements":7,
"first":true,
"sort":{},
"number":0,
"numberOfElements":7,
"size":20
}
Here I leave my appreciation and gratitude for the community beforehand. Cheers,
André Castro.
Then use only the desired properties in your object, making sure to follow the structure of the desired model.
public partial class RootObject {
[JsonProperty("content")]
public Content[] Content { get; set; }
}
public partial class Content {
[JsonProperty("solverSolution")]
public SolverSolution SolverSolution { get; set; }
}
public partial class SolverSolution {
[JsonProperty("id")]
public Guid Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("maxHeight")]
public double MaxHeight { get; set; }
[JsonProperty("layers")]
public long Layers { get; set; }
[JsonProperty("solution")]
public Solution[] Solution { get; set; }
[JsonProperty("default")]
public bool Default { get; set; }
}
public partial class Solution {
[JsonProperty("X1")]
public long X1 { get; set; }
[JsonProperty("Y1")]
public long Y1 { get; set; }
[JsonProperty("Z1")]
public long Z1 { get; set; }
[JsonProperty("X2")]
public long X2 { get; set; }
[JsonProperty("Y2")]
public long Y2 { get; set; }
[JsonProperty("Z2")]
public long Z2 { get; set; }
}
The parser will ignore the rest that do not map to properties of the object model.
var root = Jsonsonvert.DeserializeObject<RootObject>(jsonWeb);
var solverSolution = root.Content[0].SolverSolution;
How can I get all SolverSolution
SolverSolution[] solutions = root.Content.Select(content => content.SolverSolution).ToArray();
I use:
JsonConvert.DeserializeObject<dynamic>(stringInput)
to get anonymouse type I need
Then you can use something like this to get specific part:
var obj = JsonConvert.DeserializeObject<dynamic>(input)["content"][0]["solverSolution"];
It's easy and gets me job done.
Edit:
Side note, please next time when you upload json just cut off parts that are not needed so I can serialize it, took me some time to fix it :D
You can use a JObject to parse all Json. Then, you can map a specific children to your object.
Reference
{
"578080": {
"success": true,
"data": {
"type": "game",
"name": "PLAYERUNKNOWN'S BATTLEGROUNDS",
"steam_appid": 578080,
"required_age": 0,
"is_free": false,
}
}
}
This is from the Steam API. As you can see the root key the ID itself, so I don't know how to deserialize this to an object. I've seen other questions regarding unknown property names, but can't seem to apply those solutions for when the root name is unknown.
One way to do this is to Deserialize to Dictionary
Classes
public class Data
{
public string type { get; set; }
public string name { get; set; }
public int steam_appid { get; set; }
public int required_age { get; set; }
public bool is_free { get; set; }
}
public class SomeClass
{
public bool success { get; set; }
public Data data { get; set; }
}
Usage
var result = JsonConvert.DeserializeObject<Dictionary<string, SomeClass>>(json);
If you don't care about making POCO models for your deserialized data and just want to grab some of the properties using a dynamic, you can use JsonExtensionData to get a JToken of the relevant subobject:
public class Foo
{
[JsonExtensionData]
public Dictionary<string, JToken> ExtensionData {get; set;}
}
dynamic obj = JsonConvert.DeserializeObject<Foo>(json).ExtensionData.Single().Value;
Console.WriteLine(obj.success);
Console.WriteLine(obj.data.name);
This approach would be particularly useful if you could reuse Foo across several different types of responses since it doesn't care at all about the object schema.
You can use an anonymous type deserialization to parse JSON data like this, without creating classes. I assumed there is only one Id("578080") present in your data.If more Id's present, you can create an array for those Id's. Hope It Works.
var finalResult=JsonConvert.DeserializeAnonymousType(
yourdata, // input
new
{
Id=
{
new
{
success="", data=""
}
}
}
);
console.write(finalResult.Id);// getting Id 578080
console.write(finalResult.Id.success);
console.write(finalResult.Id.data.type);
I've got some difficulties with this json script:
{
"insured_agent_flag": "a",
"id": "1",
"agent": {
"fullName": "John Travolta",
"mobileNumberPdf": "+987654321",
"mobileNumber": "",
"identityCard": {
"identityCardExpirationDate": null
},
"secondIdentityCard": {
"identityCardExpirationDate": null
},
"notes": {},
"sign": "ADVANCED"
},
"basicData": {
"personType": "PERSON",
"agreeWithCompleteAnalysis": false,
"investmentInterest": false
},
"nonOfferedProducts": [
"PROD_A",
"PROD_B",
"PROD_C"
]
}
I would like to get some parameters from this script and put it into sql server table.
In order to do that, I used and transformed a C# script shared by https://mycontraption.com:
using System;
using System.Data;
using System.Collections.Generic;
using System.Linq;
using Microsoft.SqlServer.Dts.Pipeline.Wrapper;
using Microsoft.SqlServer.Dts.Runtime.Wrapper;
using System.Web.Script.Serialization;
using Microsoft.SqlServer.Dts.Pipeline;
namespace SC_c7e2d8c3918d46a5a07a1b438ddc7642
{
public class BasicData
{
public string agreeWithCompleteAnalysis { get; set; }
public string inOtherSystem { get; set; }
public string investmentInterest { get; set; }
}
public class ParentObject
{
public BasicData BasicData { get; set; }
public int id { get; set; }
public string insured_agent_flag { get; set; }
public IEnumerable<string> NonOfferedProducts { get; set; }
}
[Microsoft.SqlServer.Dts.Pipeline.SSISScriptComponentEntryPointAttribute]
public class ScriptMain : UserComponent
{
public override void Input0_ProcessInputRow(Input0Buffer Row)
{
JavaScriptSerializer js = new JavaScriptSerializer();
// Give the input column a variable to make it easier to reference.
BlobColumn combinedColumn = Row.parameterscon;
// Convert from blob to string
string reviewConverted = System.Text.Encoding.ASCII.GetString(combinedColumn.GetBlobData(0, Convert.ToInt32(combinedColumn.Length)));
// Deserialize the string
ParentObject obj = js.Deserialize<ParentObject>(reviewConverted);
var rows = obj.NonOfferedProducts.ToList();
Row.agreeWithCompleteAnalysis = obj.BasicData.agreeWithCompleteAnalysis;
Row.inOtherSystem = obj.BasicData.inOtherSystem;
Row.investmentInterest = obj.BasicData.investmentInterest;
Row.projectionid = obj.id;
Row.insuredagentflag = obj.insured_agent_flag;
//Row.nonOfferedProducts =
}
}
}
For 'standard' objects it works fine, but there is a problem with array "nonOfferedProducts". After compiling I get an error:
„object reference not set to an instance of an object”.
Here are my questions:
1. How should I handle 'nonOfferedProducts' array in C# script?
2. Why do I get foregoing error?
3. Unfortunately there exists a possibility, that json scripts would have some errors, like missing braces. How should I handle that?
Thank you!
Thanks a lot for your answers. According to your comments I'll try to give you more explanations:
1. The json script I have added in this post - it's only small part of whole script. In complete script there is a lot of different parameters. What is more, my C# code should scan about 40.000 json scripts (stored in sql server table in one column). These scripts has got similiar structure - but not the same.
So I thought about C# resolution, that will be searching for the parameters that I need. For json scripts without these parameters the c# code will put nulls to the right output columns.
Here are my output columns:
-agreeWithCompleteAnalysis
-inOtherSystem
-investmentInterest
-projectionId
-insuredAgentFflag
-nonOfferedProducts
I understood, that structure of my classes were wrong - I'll improve that.
But I've got one doubt - is it possible to prepare c# code structure, that will handle only these parameters I need?
And finally, I would like to put the results into my database.
For example if nonOfferedProducts property will have 3 values (not always!), I'd like to send to my database table 3 records (3 different values for nonOfferedProducts column and 3 the same values for the rest columns -agreeWithCompleteAnalysis, inOtherSystem etc).
I hope that will be clear now.
Thanks a lot for your help!
J
Use https://quicktype.io and paste json, it will generate c# model and serializer code.
As I said in my comment, your c# model doesn't match the JSON object.
If the model was made up of various nested objects to better reflect the actual JSON then you'll have more luck:
public class IdentityCard
{
public DateTime? IdentityCardExpirationDate { get; set; }
}
public class Notes
{
//No idea what should be in here...
}
public class BasicData
{
public string PersonType { get; set; }
public bool AgreeWithCompleteAnalysis { get; set; }
public bool InvestmentInterest { get; set; }
}
public class Agent
{
public string FullName { get; set; }
public string MobileNumberPdf { get; set; }
public string MobileNumber { get; set; }
public IdentityCard IdentityCard { get; set; }
public IdentityCard SecondIdentityCard { get; set; }
public Notes Notes { get; set; }
public string Sign { get; set; }
}
//Note: THIS is the actual class that matches the JSON sample given.
public class ParentObject
{
public string insured_agent_flag { get; set; }
public int Id { get; set; }
public Agent Agent { get; set; }
public BasicData BasicData { get; set; }
public IEnumerable<string> NonOfferedProducts { get; set; }
}
Once the model is correct, then Deserialization works fine for me with the given example (I did this in a unit test, but assuming your string matches your example this should be fine)
//get json
string json = #"
{
""insured_agent_flag"": ""a"",
""id"": ""1"",
""agent"": {
""fullName"": ""John Travolta"",
""mobileNumberPdf"": ""+987654321"",
""mobileNumber"": """",
""identityCard"": {
""identityCardExpirationDate"": null
},
""secondIdentityCard"": {
""identityCardExpirationDate"": null
},
""notes"": {},
""sign"": ""ADVANCED""
},
""basicData"": {
""personType"": ""PERSON"",
""agreeWithCompleteAnalysis"": false,
""investmentInterest"": false
},
""nonOfferedProducts"": [
""PROD_A"",
""PROD_B"",
""PROD_C""
]
}";
var js = new JavaScriptSerializer();
ParentObject obj = js.Deserialize<ParentObject>(json);
//do things...
var rows = obj.NonOfferedProducts.ToList();
Assert.AreEqual(3, rows.Count);
Assert.AreEqual("PROD_A", rows.First());
The asserts pass - This code happily gets the list of strings in the NonOfferedProducts property with the given example.
Obviously if you cannot rely on the consistency of the JSON (either structure or how well-formed it is) then you'll have problems, but that's a different issue.
To answer your question no 2) you are getting the object reference error because the BasicDataClass.nonOfferedProducts is null and you are trying iterate over it , this may be a reason that you are sending the wrong json which JavaScriptSerializer is not able to deserilize.
your 3rd question you can always validate your json with json validators which are there online like https://jsonformatter.org/
I'm trying to deserialize json result to wanted object. The result I'm getting is:
{
"base": "EUR",
"date": "2017-06-30",
"rates": {
"AUD": 1.4851,
"BGN": 1.9558,
"BRL": 3.76,
"CAD": 1.4785
}
}
I want this result to deserialize to my object:
public class ExchangeRates
{
public string Base { get; set; }
public DateTime Date { get; set; }
public IList<Rates> Rates { get; set; }
}
public class Rates
{
public string Name { get; set; }
public decimal Value { get; set; }
}
my deserialization looks like this:
using (var httpClient = new HttpClient())
{
var response = httpClient.GetAsync("http://api.fixer.io/latest").Result;
var result = response.Content.ReadAsStringAsync().Result;
var values = JsonConvert.DeserializeObject<ExchangeRates>(result);
}
When I run the program I get following exception:
Newtonsoft.Json.JsonSerializationException: 'Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`1[ConsoleApp4.Rates]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
To fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.
Path 'rates.AUD', line 1, position 49.'
How can I deserialize JSON to my wanted object??
UPDATE 1
Or maybe I can just deserialize 'rates' list?
Take a look at your JSON, specifically rates:
"rates": {
"AUD": 1.4851,
"BGN": 1.9558,
"BRL": 3.76,
"CAD": 1.4785
}
This is very clearly a JSON object, as it has key-value pairs. However, looking at your code, you have defined the corresponding property (Rates) as an IList:
public IList<Rates> Rates { get; set; }
I understand your reasoning behind defining the Rates class. You think that by defining that class, NewtonSoft will deserialize rates the way you want it to. However, this is impossible because rates is not an array, and therefore deserializing it into any kind of IList is impossible.
The easiest and most clear cut solution is to use a dictionary:
public Dictionary<string, decimal> Rates { get; set; }
However, if you don't want to use a dictionary, you need to modify your JSON like so and your solution will work:
"rates":[
{
"Name":"AUD",
"Value":1.4851
},
{
"Name":"BGN",
"Value":1.9558
},
{
"Name":"BRL",
"Value":3.76
},
{
"Name":"CAD",
"Value":1.4785
}
]
By converting rates to an array, and making its contents objects instead of key-value pairs, NewtonSoft can deserialize rates as a list, and its contents as instances of the Rates class.
I agree with the other guys comments: you should use a Dictionary. To achieve the conversion to your final object structure you can use for example an intermediary class with an explicit cast operator.
using System;
using Newtonsoft.Json;
using System.Collections.Generic;
public class Program
{
public void Main()
{
var result = #"{
""base"": ""EUR"",
""date"": ""2017-06-30"",
""rates"": {
""AUD"": 1.4851,
""BGN"": 1.9558,
""BRL"": 3.76,
""CAD"": 1.4785
}}";
var values = (ExchangeRates) JsonConvert.DeserializeObject<TempExchangeRates>(result);
Console.WriteLine(values.Base);
Console.WriteLine(values.Date);
foreach(var rate in values.Rates)
Console.WriteLine(rate.Name + ": " + rate.
}
}
public class TempExchangeRates
{
public string Base { get; set; }
public DateTime Date { get; set; }
public Dictionary<string,decimal> Rates { get; set; }
public static explicit operator ExchangeRates(TempExchangeRates tmpRates)
{
var xRate = new ExchangeRates();
xRate.Base = tmpRates.Base;
xRate.Date = tmpRates.Date;
xRate.Rates = new List<Rates>();
foreach(var de in tmpRates.Rates)
xRate.Rates.Add(new Rates{Name = de.Key, Value = de.Value});
return xRate;
}
}
public class ExchangeRates
{
public string Base { get; set; }
public DateTime Date { get; set; }
public IList<Rates> Rates { get; set; }
}
public class Rates
{
public string Name { get; set; }
public decimal Value { get; set; }
}
I'm currently using a beta API (http://developer.riotgames.com/api/methods) which returns JSON for all the exposed methods.
I've been able to use JSON.NET to deserialize all of these return values so far. However, today I consumed one of their function which returns a JSON that is valid but is in my opinion not correct.
You're probably wondering, why don't you ask it on the beta forum? I have but I haven't received an answer so far and in general this intrigues me.
A snippet of the JSON return:
"1001": {
"name": "Boots of Speed",
"plaintext": "Slightly increases Movement Speed",
"group": "BootsNormal",
"description": "<...
}
The problem I have with this structure is that the ID is used as a "group" without an identifier. I would be able to use this decently if it had
"ItemID" : "1001"
But it doesn't have that. I don't mind manually parsing it but I'd first like to know whether or not this JSON is correct (not just valid).
Do you agree that this is not a clean way of creating a JSON block that contains a list of elements or am I missing something here? So far I haven't seen any comments on the beta forum of this API so I'm really wondering why.
Edit "valid" vs "correct/usable":
I know it's a valid JSON statement. I'm questioning the fact whether this is usable with JSON.NET.
I have the following class definition (with two subclasses):
public class JSONItem
{
[JsonProperty("tags")]
public string[] Tags { get; set; }
[JsonProperty("plaintext")]
public string Plaintext { get; set; }
[JsonProperty("description")]
public string Description { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("into")]
public string[] Into { get; set; }
[JsonProperty("image")]
public JSONItemImage Image { get; set; }
[JsonProperty("colloq")]
public string Colloq { get; set; }
[JsonProperty("gold")]
public JSONItemGold Gold { get; set; }
}
When giving the above JSON block to to JSONConvert.DeserializeObject(json) it throws an error because "1001" is not mentioned in JSONItem.
How do you handle this so that you can use JSON.NET?
A class like this won't work because you have no names to give the properties:
public class JSONItemWrapper
{
[JsonProperty("")]
public string ID { get; set; }
[JsonProperty("")]
public JSONItem MyProperty { get; set; }
}
Edit: "consistent with other methods"
The other methods return blocks where every property is within {} and has an identifier. The most recently added function have this "primary key outside of {}" style.
It is a valid json and you can use a type like Dictionary<string, SomeObject> to deserialize your json.
string json = #"{
""1001"": {
""name"": ""Boots of Speed"",
""plaintext"": ""Slightly increases Movement Speed"",
""group"": ""BootsNormal"",
""description"": ""desc...""
}
}";
var dict = JsonConvert.DeserializeObject<Dictionary<string, MyObject>>(json);
and accesing an item later on by its key can be fast too.
public class MyObject
{
public string name { get; set; }
public string plaintext { get; set; }
public string group { get; set; }
public string description { get; set; }
}
It's annoying when APIs do things like this (using numbers as property names), but all is not lost. Simply deserialize the JSON using Json.NET and then access each of the items using the indexer operator on the parent object.
EDIT:
I almost never create DTOs when deserializing JSON. It's lots of unnecessary boilerplate in most cases. I prefer deserializing to a dynamic object, but that won't be as effective when dealing with property names that begin with digits.
Here is how I would deserialize your sample message:
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace JsonExample
{
internal class Program
{
private static void Main()
{
const string json = #"
{
'1001': {
'name': 'Boots of Speed',
'plaintext': 'Slightly increases Movement Speed',
'group': 'BootsNormal',
'description': '<...'
}
}";
var jObject = JsonConvert.DeserializeObject<JObject>(json);
var plaintext = jObject["1001"]["plaintext"].Value<string>();
Console.WriteLine(plaintext);
}
}
}
When put into http://JSONLint.com,
{
"1001": {
"name": "Boots of Speed",
"plaintext": "Slightly increases Movement Speed",
"group": "BootsNormal",
"description": "<..."
}
}
Validates as JSON.