C# Dynamic Type Initialization From JSON - c#

I am trying to dynamically instantiate a class from my visual studio solution based on a JSON string.
Before I describe my exact issue I want to give an example of what I want to achieve.
Say I have the following JSON :
{
"Type": "AutoIncrementTag,
"StartFrom": 0,
"Skip": 10,
"LeadingZero": false
}
So from that Json, I want to find the class called "AutoIncrementTag" and instantiate it, setting its "StartFrom", "Skip" and "LeadingZero" parameters to the correspoding values.
Note 1: I have a couple of theese "Tag" classes and I want to instantiate a different on the "Type" attribute in my Json string.
Note 2: My Json string will contain more than 1 of these class "descriptions" (I believe they are called JSON Objects but I'm not too familliar with the JSON format just yet)
Note 3: I am using Newtonsoft.Json for all the Json parsing/converting.
So, now for my issue.
I managed to get the Type property using
JObject.Parse(myJsonString).GetValue("Type").ToString();
However, how would I go about getting all the other values, since they will be different depending on what Type I have? (I need a way to dynamically iterate and get the values of the other properties.)
And second, how do I then map these properties to a C# object.
I thought about using
Activator.CreateInstance(Type type, object[] args)
But how can I (dynamically) get an object[] from the properties described in my json format.

JSON.Net (i.e. Newtonsoft.Json) does this for you already. For example, lets start off with a basic class:
public class Thing
{
public int SomeValue { get; set; }
public string AnotherValue { get; set; }
}
And an instance of it:
var thing = new Thing { SomeValue = 5, AnotherValue = "blah" };
We can deserialise with a custom settings object, specifically setting the TypeNameHandling property
var settings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All
};
var json = JsonConvert.SerializeObject(thing, settings);
Which will give output something like this:
{
"$type":"Thing, Namespace",
"SomeValue": 5,
"AnotherValue": "blah"
}
And to get it back into the right kind of object, just use the same settings:
var anotherThing = JsonConvert.DeserializeObject(json, settings);

Related

Use set acessor during JSON deserialization

Let's say I have an instance of a class like this which I want to serialize to JSON:
public class MyClass
{
public MyClass() { }
private List<string> texts;
public List<string> Texts
{
get
{
return new List<string> { "You got me!" };
}
set
{
texts = value;
Console.WriteLine("Setting property!");
}
}
}
I want to to make sure the set accessor for "Texts" is called during deserialization, i.e make sure that the private property "texts" in MyClass gets set. However, if I run a small test case:
public void TestMyClass()
{
var myClass = new MyClass();
var jsonBefore = JsonConvert.SerializeObject(myClass);
var jsonAfter = JsonConvert.DeserializeObject<MyClass>(jsonBefore);
}
The set method never gets called, i.e private "texts" is null after deserialization. How can I make sure that the set accessor in public "Texts" gets called during deserialization?
The first reason is because you use newtonsoft json serializer that is quite different from built in .net one.
var json = new JavaScriptSerializer().Serialize(myClass);
var obj = new JavaScriptSerializer().Deserialize<MyClass>(json);
This code is going to work fine.
The second reason is in your get property and how it's processed by newtonsoft json serializer, you have default list creating (it is better to put it into constructor as as it made now doesn't make any sense)
If you still want to use your get as it implemented now, use JsonSerializerSettings.ObjectCreationHandling setting for customizing object creating,
var jsonBefore = JsonConvert.SerializeObject(myClass);
var jsonAfter = JsonConvert.DeserializeObject<MyClass>(jsonBefore, new JsonSerializerSettings
{
ObjectCreationHandling = ObjectCreationHandling.Replace
});
If you don't want to set null in Texts property then you can set default value to it.
Like private List<string> texts = new List<string>(){ "Default Value" };
and instead of
get
{
return new List<string> { "You got me!" };
}
you should use
get
{
return texts;
}
Serialization is the process of translating data structures or object state into a format that can be stored (in our case it's json).
Object state consists of fields values, all methods or other behavioral logic is simply ignored.
Properties are basically methods that work with backing fields so they're not used on serialization / deserialization because they do not represent object's state.
In our case field texts is serialized with use of reflection. Then it is deserialized directly and it is possible that serializer doesn't even know that property exists.

Accessing properties with a dot in their name

I am trying to deserialize JSON. My root object has a single property "en.pickthall". I am using dynamic type for reading my JSON. I thought I could just do away with "." in the property since its a local JSON file but then there must be some way to access such a property
var result = App_Code.FileIOHelper.ReadFromDefaultFile("ms-appx:///Assets/en.pickthall.json");
dynamic stuff = JsonConvert.DeserializeObject(result);
foreach(var x in stuff.(en.pickthall)) //Tried this intellisense didn't like it
{
}
You could create a root class to deserialize into and use JsonProperty
public class Root
{
// Use the proper type instead of object
[JsonProperty(PropertyName = "en.pickthall")]
public IEnumerable<object> EnPickthall { get; set; }
public Root() { }
}
Used as follows
Root stuff = JsonConvert.DeserializeObject<Root>(result);
foreach(var x in stuff.EnPickthall)
{
}
You could serialize not to dynamic but to JObject and then access your property via
JObject stuff = JsonConvert.DeserializeObject<JObject>(Jsonstring);
var x = stuff.Value<String>("my.property")
C# doesn't have any way of quoting identifiers. If it's not a valid identifier, your only option is reflection.
However, it's possible the object returned by your JSON deserializer changed the identifiers to make them useable in C# - you might want to enumerate all the properties to check if that is the case. A dynamic object with indexers might also be a solution (allowing e.g. stuff["en.pickthall"]).
Another alternative is to change the way the serializer maps properties. For example, Newtonsoft.Jsoft allows you to customize this using a IContractResolver. It's quite easy to replace the . for something more C#-sane in this way.
I know you said you were using a dynamic type for your JSON deserialization, but I just wanted to point out that there is a .NET RESTful client out there that supports this with static model definitions too. For you or for anyone else who happens upon this response when searching for an answer to their problems with dots in property names in C# REST calls.
As of the newly released RestSharp 106.1.0 (and I do mean this version because this support was just added), it can handle renaming properties with a dot in their name via the DeserializeAs attribute. An example being when I call the ElasticSearch API for a _cat call with the following model:
public class CatResponse
{
public string index { get; set; }
...
[DeserializeAs(Name = "docs.count")]
public string docscount { get; set; }
}
And actually get back the docs.count property deserialized into docscount now:
var resource = $"_cat/indices/{indexPattern}?format=json&pretty=true";
var request = new RestRequest(resource, Method.GET);
var response = client.Execute<List<CatResponse>>(request);
This support is out of the box and doesn't need to use the Newtonsoft.Json.JsonSerializer which I have also heard is a possible solution to this problem but which I couldn't get to work.
With a dynamic object and NewtonSoft.Json:
dynamic json = JValue.Parse(result);
int Opens = Convert.ToInt32(json.opens);
int Clicks = Convert.ToInt32(json.clicks);
string State = json.state;

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.

Deserialization of JSON object by using DataContractJsonSerializer in C#

I'm sure this question has been asked over and over again, but for some reason, I still can't manage to get this to work.
I want to deserialize a JSON object that contains a single member; a string array:
[{"idTercero":"cod_Tercero"}]
This is the class that I'm trying to deserialize into:
[DataContract]
public class rptaOk
{
[DataMember]
public string idTercero { get; set; }
public rptaOk() { }
public rptaOk(string idTercero)
{
this.idTercero = idTercero;
}
}
This is the method that I try to deserialize:
public T Deserialise<T>(string json)
{
DataContractJsonSerializer deserializer = new DataContractJsonSerializer(typeof(T));
using (MemoryStream stream = new MemoryStream(Encoding.Unicode.GetBytes(json)))
{
T result = (T)deserializer.ReadObject(stream);
return result;
}
}
And so I try to fill the object:
rptaOk deserializedRpta = deserializarOk(rpta);
But for some reason, this returns ""
MessageBox.Show(deserializedRpta.idTercero);
Without any dependencies outside of the .net framework, you could do it this way
[DataContract(Name="rptaOk")]
public class RptaOk
{
[DataMember(Name="idTercero")]
public string IdTercero { get; set; }
}
[CollectionDataContract(Name="rptaOkList")]
public class RptaOkList : List<RptaOk>{}
var stream = new StreamReader(yourJsonObjectInStreamFormat);
var serializer = new DataContractSerializer(typeof(RptaOkList));
var result = (RptOkList) serializer.ReadObject(stream);
I don't know if your're wiling to change the library that you're using, but I use library "Newtonsoft.Json" to desserialize JSON objects, it's pretty easy to use
[HttpPost]
public void AddSell(string sellList)
{
var sellList = JsonConvert.DeserializeObject<List<Sell>>(sellListJson);
BD.SaveSellList(sellList);
}
As you can see you can deserialize a whole json object list to a List<> fo the type "Sell", an object that i've created... And, of course, you can do that to an array too. I don't know the correct syntax for this, but you can convert this list to an array afterwards
Hope this helps
I think you're making this a lot more difficult than it needs to be. Firstly, your sample json and the class you're trying to deserialize into do not have an array of strings. They have a single property of type string. Secondly, why are you using this class DataContractJsonSerializer? You're not doing anything with it that you can't get from a simple call to json.NET's generic deserialization method. I would remove all of your code except the class definition and replace it with this simple one liner;
rptaOk[] myInstances = JsonConvert.DeserializeObject<rptaOk>(jsonString);
Also, no matter what the structure of your json is, if you have a class to correctly model it that method will correctly deserialize it. If you want to enforce some kind of contract I recommend using json schemas which json.NET also supports. If you use a schema it enforces a rigid contract, if you attempt to deserialize into an object there is something of an implicit contract. I don't know every scenario which will cause it to throw, but if your json is too far from the class definition it will. If your class has properties that don't appear in the json I believe they will just get initialized with the default values for that type.
EDIT: I just noticed your json is actually an array of objects. So you simply need to make the lhs of that assignment an array or rptaOk objects, rather than a singleton.

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