Deserializing JSON into an object - c#

I have some JSON:
{
"foo" : [
{ "bar" : "baz" },
{ "bar" : "qux" }
]
}
And I want to deserialize this into a collection. I have defined this class:
public class Foo
{
public string bar { get; set; }
}
However, the following code does not work:
JsonConvert.DeserializeObject<List<Foo>>(jsonString);
How can I deserialize my JSON?

That JSON is not a Foo JSON array. The code JsonConvert.DeserializeObject<T>(jsonString) will parse the JSON string from the root on up, and your type T must match that JSON structure exactly. The parser is not going to guess which JSON member is supposed to represent the List<Foo> you're looking for.
You need a root object, that represents the JSON from the root element.
You can easily let the classes to do that be generated from a sample JSON. To do this, copy your JSON and click Edit -> Paste Special -> Paste JSON As Classes in Visual Studio.
Alternatively, you could do the same on http://json2csharp.com, which generates more or less the same classes.
You'll see that the collection actually is one element deeper than expected:
public class Foo
{
public string bar { get; set; }
}
public class RootObject
{
public List<Foo> foo { get; set; }
}
Now you can deserialize the JSON from the root (and be sure to rename RootObject to something useful):
var rootObject = JsonConvert.DeserializeObject<RootObject>(jsonString);
And access the collection:
foreach (var foo in rootObject.foo)
{
// foo is a `Foo`
}
You can always rename properties to follow your casing convention and apply a JsonProperty attribute to them:
public class Foo
{
[JsonProperty("bar")]
public string Bar { get; set; }
}
Also make sure that the JSON contains enough sample data. The class parser will have to guess the appropriate C# type based on the contents found in the JSON.

Related

Converter that uses generics to parse json model

I have a converter class that receives json in input, here are 2 valid examples:
{
"method": "Model",
"payload": {
"key": "value"
}
}
and
{
"method": "OtherModel",
"payload": {
"foo": "bar"
}
}
In C#, I have classes mapped to each possible model:
public class Model
{
public string Key { get; set; }
}
public class OtherModel
{
public string Foo { get; set; }
}
I need a generic converter
How can I use the string value in the method of the JSON to convert in a generic way the content of the payload field?
Is using a huge switch the only way? This is the prototype I have so far but there are hundreds of different models so it will grow quite large...
public IResult ParseJson(string json)
{
Regex regexMessageName = new Regex("\"messageName\": \"(.*?)\"", RegexOptions.Compiled);
var messageName = regexMessageName.Match(json).Groups[1].Value;
switch (messageName)
{
case "Model":
var raw = JsonConvert.DeserializeObject<JsonData<Model>>(json);
return new LogInfoRequestResult<Model> { Raw = raw };
case "OtherModel":
var raw = JsonConvert.DeserializeObject<JsonData<OtherModel>>(json);
return new LogInfoRequestResult<OtherModel> { Raw = raw };
}
}
If you want complete control of your classes, and allow them to evolve independently, then you can have one base class that owns the Method, and then as many subclasses as you want with their own definition of the payload.
First, parse into the baseclass, just to get a strongly typed deserialization of Method
Then, there are a lot of patterns to address branching logic.
If you have 1-2 cases, an if statement is fine
If you have 3-5 cases, you can use a switch
If you have 6-10 cases, you can create a dictionary that maps method name to class type
If you have more than that, you can use the strategy pattern and pass an interface around
Here's an example of how you could write the code:
var json = #"{
'method': 'Model',
'payload': {
'key': 'value'
}
}";
var modelBase = JsonConvert.DeserializeObject<ModelBase>(json);
var methodMapping = new Dictionary<string, Type>()
{
{MethodTypes.Model.ToString(), typeof(Model)},
{MethodTypes.OtherModel.ToString(), typeof(OtherModel)},
};
Type methodClass = methodMapping[modelBase.Method];
var result = JsonConvert.DeserializeObject(json, methodClass);
Note: Since we're programmatically determining the correct type, it's hard to pass to a generic <T>, so this uses the overload of DeserializeObject that takes type as a param
And here are the classes that model incoming messages
public enum MethodTypes
{
Model,
OtherModel
}
public class ModelBase
{
public string Method { get; set; }
}
public class Model : ModelBase
{
public ModelInfo Payload { get; set; }
public class ModelInfo
{
public string Key { get; set; }
}
}
public class OtherModel : ModelBase
{
public ModelInfo Payload { get; set; }
public class ModelInfo
{
public string Foo { get; set; }
}
}
Dictionary<string,string>
If your data is always going to be "foo":"bar" or "key":"value" .... string:string, then Cid's suggesting to use Dictionary<string,string> Payload makes a lot of sense. Then figure out however you want to map from that c# class in a c# constructor that returns whatever type you want.
Additional Resources:
How to handle both a single item and an array for the same property using JSON.net
Deserializing polymorphic json classes without type information using json.net
JSON.NET - Conditional Type Deserialization
Conditionally deserialize JSON string or array property to C# object using JSON.NET?
You can instanciate an object of the expected class using Activator.CreateInstance(), then populate it with JsonConvert.PopulateObject()
In example :
Type t = Type.GetType($"NameSpaceName.{messageName}"); // this must be a fully qualified name
object obj = Activator.CreateInstance(t);
JsonConvert.PopulateObject(json, obj);

This JSON string won't get deserialized [duplicate]

I have some JSON:
{
"foo" : [
{ "bar" : "baz" },
{ "bar" : "qux" }
]
}
And I want to deserialize this into a collection. I have defined this class:
public class Foo
{
public string bar { get; set; }
}
However, the following code does not work:
JsonConvert.DeserializeObject<List<Foo>>(jsonString);
How can I deserialize my JSON?
That JSON is not a Foo JSON array. The code JsonConvert.DeserializeObject<T>(jsonString) will parse the JSON string from the root on up, and your type T must match that JSON structure exactly. The parser is not going to guess which JSON member is supposed to represent the List<Foo> you're looking for.
You need a root object, that represents the JSON from the root element.
You can easily let the classes to do that be generated from a sample JSON. To do this, copy your JSON and click Edit -> Paste Special -> Paste JSON As Classes in Visual Studio.
Alternatively, you could do the same on http://json2csharp.com, which generates more or less the same classes.
You'll see that the collection actually is one element deeper than expected:
public class Foo
{
public string bar { get; set; }
}
public class RootObject
{
public List<Foo> foo { get; set; }
}
Now you can deserialize the JSON from the root (and be sure to rename RootObject to something useful):
var rootObject = JsonConvert.DeserializeObject<RootObject>(jsonString);
And access the collection:
foreach (var foo in rootObject.foo)
{
// foo is a `Foo`
}
You can always rename properties to follow your casing convention and apply a JsonProperty attribute to them:
public class Foo
{
[JsonProperty("bar")]
public string Bar { get; set; }
}
Also make sure that the JSON contains enough sample data. The class parser will have to guess the appropriate C# type based on the contents found in the JSON.

JSON deserialization throws exception when nested object is empty

Hello I have a problem with deserializing JSON to object.
I have this kind of JSON:
{
"my_obj":{
"id":"test",
"nested_obj":{
"value":"testValue",
"desc":"testDesc"}
}
}
But sometimes I receive empty nested_obj:
{
"my_obj":{
"id":"test",
"nested_obj":""
}
}
My code to handle this:
public class MyObj
{
public string id { get; set; }
public NestedObj nested_obj { get; set; }
}
public class NestedObj
{
public string value { get; set; }
public string desc { get; set; }
}
public virtual T Execute<T>(IRestRequest request) where T : new()
{
request.RequestFormat = DataFormat.Json;
var response = _client.Execute<T>(request);
LogResponse(response);
CheckResponseException(response);
return response.Data;
}
When the nested_obj is not empty, then deserialization works perfectly fine. But when nested_obj is empty, I receive this exception:
Unable to cast object of type 'System.String' to type 'System.Collections.Generic.IDictionary`2[System.String,System.Object]'.
Is it possible to deserialize it this way? Unfortunately it is not possible to change response of the WebService, so i should parse it correctly in my app.
Simply use Newtonsoft's Json.NET. It works fine. Here's a short snippet from LINQPad:
void Main()
{
JsonConvert.DeserializeObject<A>(#"{
property: ""apweiojfwoeif"",
nested: {
prop1: ""wpeifwjefoiwj"",
prop2: ""9ghps89e4aupw3r""
}
}").Dump();
JsonConvert.DeserializeObject<A>(#"{
property: ""apweiojfwoeif"",
nested: """"
}").Dump();
}
// Define other methods and classes here
class A {
public string Property {get;set;}
public B Nested {get;set;}
}
class B {
public string Prop1 {get;set;}
public string Prop2 {get;set;}
}
And the result is
Ouch. That has nothing to do with your code as you already know. It's just that the web service is sometimes defining nested_obj as a NestedObj object, and sometimes as a string (when it sends null). So your parser doesn't know what to make of it.
Your best bet might be to write a custom parser for it. (which makes sense since it's not standard JSON due to the type morphing).
There's a section on writing a custom parser for RestSharp here
They tell you to implement IDeserializer but I'd suggest you simply extend JsonDeserializer to add your special custom functionality and delegate back to the super class for everything else.
Reason is because in
{
"my_obj":{
"id":"test",
"nested_obj":{
"value":"testValue",
"desc":"testDesc"}
}
}
nested object is receiving an object type
while in
{
"my_obj":{
"id":"test",
"nested_obj":""
}
}
it is receiving string type.
if
it returns
{
"my_obj":{
"id":"test",
"nested_obj":null
}
}
then it will be able to parse successfully.
try using http://json2csharp.com/ to convert both of your json and see the difference

Auto-generate C# classes from JSON, including property initializers

There are a number of great ways to auto-generate C# code from JSON, such as here and here.
However, the resulting code doesn't include property initializers. For example, the following JSON:
{
"Name" : "Blastoise"
}
gets deserialized to this:
public class RootObject
{
public string Name { get; set; }
}
Presumably this is by design, since the values used in the JSON will probably be overridden anyways, so adding initializers might just annoy people who don't want them.
But what if I want that? Short of manually adding every value by hand, is there a way to deserialize JSON to the following?
public class RootObject
{
public string Name { get; set; } = "Blastoise";
}
Obviously in this case a manual edit is easy, but manual editing becomes tedious for larger JSON objects.
is there a way to deserialize JSON to the following?
Using the source code of the converter you mentioned.
A quick change at the line 204
sw.WriteLine(prefix + "public {0} {1} {{ get; set; }} = {2};", field.Type.GetTypeName(), field.MemberName, field.GetExamplesText());
gives me the result similar to what you described
internal class SampleResponse1
{
[JsonProperty("Name")]
public string Name { get; set; } = "Blastoise";
}

Serialize subclass with Json.NET

I am trying to use Json.NET to serialize a subclass. The resulting json contains the serialized properties for the superclass but not the properties on the subclass object.
This seems to be related to an issue I found here on SO. But having to write a JsonConverter seems like overkill.
Sample subclass:
public class MySubclass : List<string>
{
public string Name { get; set; }
}
Sample of the serialization:
MySubclass myType = new MySubclass() { Name = "Awesome Subclass" };
myType.Add("I am an item in the list");
string json = JsonConvert.SerializeObject(myType, Newtonsoft.Json.Formatting.Indented);
Resulting json:
[
"I am an item in the list"
]
I expected to result to be more like this:
{
"Name": "Awesome Subclass",
"Items": [
"I am an item in the list"
]
}
Perhaps I am just not using the right configuration when serializing. Anyone have any suggestions?
According the documentation:
.NET lists (types that inherit from IEnumerable) and .NET arrays are
converted to JSON arrays. Because JSON arrays only support a range of
values and not properties, any additional properties and fields
declared on .NET collections are not serialized.
So, don't subclass List<T>, just add a second property.
public class MyClass
{
public List<string> Items { get; set; }
public string Name { get; set; }
public MyClass() { Items = new List<string>(); }
}
Here are my thoughts on this. I would think that your expected results would be more consistent with a class like this:
public class MyClass
{
public string Name { get; set; }
public List<string> Items { get; set; }
}
I would not expect to see an Items element in the serialized result for MySubclass : List<string> since there is no Items property on List nor on MySubclass.
Since your class MySubclass is actually a list of strings, I would guess (and I am just guessing here) that the SerializeObject method is merely iterating through your object and serializing a list of strings.

Categories