Access JSON fields with numeric keys - c#

I want to access some address of pictures in a JSON, but the field name is a number and in c# a number is not a valid name for a variable...
My JSON:
{
"id":3441,
"name":"test",
"address": {
"1":"url.com\/45.jpg",
"2":"url.com\/23.jpg",
"3":"url.com\/65.jpg",
"4":"url.com\/789.jpg",
},
"count":2
}
My code in C#: (HrmlResult is my JSON)
dynamic stuff1 = Newtonsoft.Json.JsonConvert.DeserializeObject(HtmlResult);
string address= stuff1.address; //It Works
string allPics = stuff1.pic; //It Works
firstPicTextBox.Text= stuff1.pic.1; //compiler Error
secondPicTextBox.Text = stuff1.pic[2]; //runtime Error
What should I do?!
Thank you all...

You have to create Model object with properties, as in found json you're expecting.
Then, for number properties, you can use JsonProperty attribute to name the property as number, for example:
class MyModel {
[JsonProperty("2")]
public string Two {get; set;}
}
and then use DeserializeObject<MyModel> version
This is simplified example, for your object you have to maintain the hierarchy and probably have another class for 'address' property and use it as property type in the main model.

If you're able to modify the JSON, that's your best bet. What you have seems like it should be in an array:
{
"id":3441,
"name":"test",
"address":[
"url.com\/45.jpg",
"url.com\/23.jpg",
"url.com\/65.jpg",
"url.com\/789.jpg"
],
"count":2
}
From there, your address is a simple array of strings, rather than a numbered key-value pair collection.

Related

JsonConvert.SerializeObject reads the structure, but not the values

I tried this piece of source code (based on NewtonSoft's JSON NuGet library), for reading a JSON file into a JSON object:
string str_File_Content = File.ReadAllText(openFileDialog1.FileName);
Rootobject existing_root = JsonConvert.DeserializeObject<Rootobject>(str_File_Content);
... and it almost worked: all JSON objects are loaded into the existing_root and in case of arrays, the number of objects seems to be correct.
But: the values of the attributes seem not to be filled in, as you can see here:
JSON file excerpt:
{
"project": {
"common.DESCRIPTION": "Some information",
existing_root excerpt in Watch window:
Expected :existing_root.project.commonDESCRIPTION : Some information
Real result :existing_root.project.commonDESCRIPTION : null
What can I do in order to make JsonConvert.DeserializeObject() not only handle the structure, but also the values?
Your json property name contains "." symbol, which is invalid for C# property name, so you can specify correct name to use during (de)serialization with JsonPropertyAttribute:
public class Project
{
[JsonProperty("common.DESCRIPTION")]
public string commonDESCRIPTION { get; set; }
}

C# Deserializing JSON to class dependent on a type property

Let's say I have this little json snippet:
{
"Type": "Bar",
"BarOnly": "This is a string readable when deserialized to the Bar class only, as declared in my type key"
}
I also have these three classes:
public class Base
{
public enum SampleEnum
{
Bar,
Baz,
}
public SampleEnum Type
{
get;
set;
}
}
public class Bar : Base
{
public string BarOnly
{
get;
set;
}
}
public class Baz : Base
{
public string BazOnly
{
get;
set;
}
}
Based on the Type property in the json snippet, I'd like to have it deserialize to either Bar or Baz.
My first idea was to first deserialize it to the Base class, and then use its type and a switch statement to deserialize the JSON again to its respective class. (Using Newtonsoft.Json)
var type = JsonConvert.DeserializeObject<Base>(json).Type;
string message = "";
switch (type)
{
case (Base.SampleEnum.Bar):
message = JsonConvert.DeserializeObject<Bar>(json).BarOnly;
break;
case (Base.SampleEnum.Baz):
message = JsonConvert.DeserializeObject<Baz>(json).BazOnly;
break;
}
Console.WriteLine(message);
Needless to say that this process is extremely redundant, tedious and, since the switch statement is hard-coded, not very "dynamic" at all.
Another idea was to use a generic class as the base class instead and passing in the type of the actual class it should deserialize to, but then I end up with the same switch statement to figure out what that class should be.
Since you can't map enums to class types, I also thought about using a Dictionary to map the possible enum values to their class counterparts; this still makes the mapping process hard-coded though.
Is there any way I can dynamically get the corresponding class to deserialize to based on the type property of the json object?
EDIT: There seems to be some confusion about how this is supposed to be used and how the data is fetched; let me provide some background information.
I'm iterating through a directory with a lot of different spreadsheet files, mostly CSVs and XML files. Each of these feeds have a "meta file", describing how to process their content. This includes checksums, delimiters and other information. They also declare of what type their parent file is (CSV, XML etc). Hence, they share a lot of common properties (like the Base class in my example), but also have their own set of properties. They derive from an abstract class that requires them to implement a function that returns an instance of the corresponding feed processing class, initialized with values directly from within the meta class. I hope this makes sense.
#OguzOzgul commenting is correct. I've done this countless of times for objects that are composed with interfaces that need to be serialized and deserialized.
See TypeNameHandling for Newtonsoft:
https://www.newtonsoft.com/json/help/html/SerializeTypeNameHandling.htm
Your json file will look ever so slightly different:
{
"$type": "SomeNamespace.Bar",
"BarOnly": "This is a string readable when deserialized to the Bar class only, as declared in my type key"
}
If you use
new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All
}
During serialization, it will add the full type name of all objects to make sure newtonsoft knows what their type is during deserialization (given you use the same settings then). That way you do not have to write your own custom code for type detection.

How to create a generic json deserialization factory

I have a scenario where I receive json as a string. Each piece of json is formatted the same, except for a collection of items within. Take this as simplified examples:
{
"Type": "A",
"Items": [
{ "Name": "Item 1" },
{ "Name": "Item 2" }
]
}
{
"Type": "B",
"Items": [
{ "Counter": 1 },
{ "Counter": 2 }
]
}
I have the following models in code to represent this:
public enum Type
{
A, B
}
public class InstanceTypeA
{
public string Name { get; set; }
}
public class InstanceTypeB
{
public int Counter { get; set; }
}
note: in the future, the types will be extended further, say to D, E, and F for this example. All of which will have an item collection structured differently again.
And I would like to deserialize this into a model, for example:
public class Container<T>
{
public Type Type { get; set; }
public List<T> Items { get; set; }
}
where T would be either instanceTypeA or instanceTypeB
As mentioned, I receive the json shown at the top as a string. And it's the "type" enum that dictates the type of the object held in the items collection. I'm struggling to find a very generic way to implement this serialization.
I was thinking the factory pattern could help but not sure how to implement this - has anyone tackled a similar problem.
In my code, I happen to know if it's type A, B etc before actually attempting serialization. I could do this:
switch(obj.Type)
{
case A: JsonConvert.DeserializeObject<Container<A>>(obj.Json)
case B: JsonConvert.DeserializeObject<Container<B>>(obj.Json)
}
The drawback of this approach is that the calling code needs to then know its dealing with Container<A> or Container<B> etc. Which isn't generic at all. I can't get A or B to implement a common interface as they are both completely different. Bit stumped with this - I was hoping Factory pattern could help but can't see how - has anyone dealt with a similar issue before?
Thanks for any pointers in advance!
You don't want to use the Type property to dictate what type is used. When using the Newtonsoft Json serializer, you can include the type of an object in the JSON document. That way, when the serializer deserializes the string, it will understand what types to use. So you could completely drop the Type property and just check the type of object in the array. I believe you need to set the TypeNameHandling property of the settings object passed into the serializer. Once you see the serializer outputting a $type property with your objects in the JSON string, you know that you've done it right.

JsonProperty - Use different name for deserialization, but use original name for serialization?

I am retrieving JSON from an API. I am using newtonsoft (this is json.net right?) to deserialize this into a list of objects. It works.
Unfortunately I also need to pass this along to someone else as JSON (they can't call the API directly only I have access to it). I say unfortunately because I need to OUTPUT my JSON that is different from what is being received (the property names need to be different).
For example, I have a class called Person, with a property called Name. I want to get "People", so I make my request to that API to get JSON as above, and get back a list of Person. Unfortunately the API doesn't return me people with Name properties, it returns me pname. So to map this, I just do:
[JsonProperty("pname")]
This is all well and good - it converts pname to name and my class now has the value! I have a list of people with names.
Now I need to give this list of objects BACK to someone else as "Name", However when I serialize my people class back to JSON, it writes out the JSON as "pname" when I really want to write it out as "Name". I suspect it's picking up the "JsonProperty".
Is there a way to just have it use pname for deserialization, but use the original property value for serialization?
Thanks!
You can create a custom contract resolver that sets the property names back to the ones you've defined in the C# class before serilization. Below is some example code;
class OriginalNameContractResolver : DefaultContractResolver
{
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
// Let the base class create all the JsonProperties
IList<JsonProperty> list = base.CreateProperties(type, memberSerialization);
// assign the C# property name
foreach (JsonProperty prop in list)
{
prop.PropertyName = prop.UnderlyingName;
}
return list;
}
}
Use it like this;
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.Formatting = Formatting.Indented;
if (useLongNames)
{
settings.ContractResolver = new OriginalNameContractResolver();
}
string response = JsonConvert.SerializeObject(obj, settings);
Maybe I'm late to the party, but this also works:
[JsonPropertyName("pname")]
public string? PName { private get; set; }
public string? Name => PName;
You might be able to write a custom JsonConverter to do it with just one Person class, but I'd recommend having separate classes, since the data is modeled differently in the two places. Even if you don't plan to right now, you might find yourself needing to deserialize from Name or serialize to pname at some point. This also allows your classes to differ more substantially. You could use AutoMapper (or similar) to easily convert between the two. E.g.
public class PersonFromThatApi
{
[JsonProperty("pname")]
public string Name { get; set; }
}
public class Person
{
public string Name { get; set; }
}
Mapper.CreateMap<PersonFromThatApi, Person>();
Mapper.CreateMap<Person, PersonFromThatApi>();
var person1 = JsonConvert.DeserializeObject<PersonFromThatApi>(
#"{""pname"":""George""}");
Person person2 = Mapper.Map<Person>(person1);
string s = JsonConvert.SerializeObject(person2); // {"Name":"George"}
And yes, Newtonsoft.Json is the namespace of Json.NET. Don't ask me why they chose totally different names for those two things.
The simple solution is to create two properties.

RestSharp/Json.NET Serialize Array as JSON Object

I have a slight situation. I'm interacting with a web service using RestSharp, where the service is requiring me to send the following as part of the request:
{
"a":"a value",
"b":"b value"
}
Which is all fine and dandy, because you could simply use a class such as this:
public class MyClass
{
public string A { get; set; }
public string B { get; set; }
}
However, I do not know know the property names at runtime. Therefore, I attempted to use an ExpandoObject, but of course, this simply serialized as a JSON array:
[
"a":"a value",
"b":"b value"
]
So, it would seem that I need to be able to serialize (and deserialize) a Dictionary (or IEnumerable<KeyValuePair<string, string>>) as a JSON object (in other words, use curly braces instead of a brackets).
Does anyone know how I might do this, preferably by using a Json.NET attribute, such that the functionality may be reused elsewhere?
how about using a JObject?
var obj = new JObject();
obj["One"] = "Value One";
obj["Two"] = "Value Two";
obj["Three"] = "Value Three";
var serialized = obj.ToString(Formatting.None);
gives you
{"One":"Value One","Two":"Value Two","Three":"Value Three"}
Use JavascripSerializer object from .net class libs. It supports reflection on the object it is serializing
see msdn docs

Categories