Passing class name as parameter to JsonConvert.DeserializeObject - c#

I am trying to compare return values of different rest api json responses, and i would like to create a method that takes a class name as a paremeter like the following. I have tried submitting as string and typeof(). would like to know what's the right way to pass ClassName as a parameter or if i should take a different approach.
class Employee
{
//different properties
}
class Patient
{
//different properties
}
class Tests
{
public bool compareValues(ClassName)
{
string expectedValues = File.ReadAllText(filePath);
var expectedValues = JsonConvert.DeserializeObject<ClassName[]>(fileResult, new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() });
//similar thing: call rest api as above.
//compare logic
}
}
Thanks for the help!

It's called generics. See example below:
public bool compareValues<T>(ClassName)
{
string expectedValues = File.ReadAllText(filePath);
var expectedValues = JsonConvert.DeserializeObject<T[]>(fileResult, new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() });
//similar thing: call rest api as above.
//compare logic
}
var employeeResult = compareValues<Employee>();
var patientResult = compareValues<Patient>();
Note method signature was changed and it contains <T> - a placeholder for class name. This will work if you already know which classes are used in your method. If you have only class name as a string, you have to deserialize your json without specifying concrete class JsonConvert.DeserializeObject(jsonString) and work with JObject (see Json.Net documentation)

Related

Serialize a JSON object without property name having a list of custom object in C#

I have model as below:
public class CustomModel
{
public string Data1 { get; set; }
public string Data2 { get; set; }
}
public class root
{
public List<CustomModel> data { get; set; }
}
My payload is as below:
List<CustomModel> cms = new List<CustomModel>();
CustomModel cm1 = new CustomModel();
cm1.Data1 = "a";
cm1.Data2 = "b";
cms.Add(cm1);
CustomModel cm2 = new CustomModel();
cm2.Data1 = "D";
cm2.Data2 = "E";
cms.Add(cm2);
BaseClass baseClass = new BaseClass();
baseClass.data = cms;
My JSON is:
var json = new JavaScriptSerializer().Serialize(baseClass);
And Result is:
{"data":[{"data1":"a","data2":"b"},{"data1":"D","data2":"E"}]}
BUT I need: without the "data" property as below:
{[{"data1":"a","data2":"b"},{"data1":"D","data2":"E"}]}
I tried the below function:
public static IEnumerable<object> GetPropertyValues<T>(T input)
{
return input.GetType()
.GetProperties()
.Select(p => p.GetValue(input));
}
Like
var value_only = GetPropertyValues(baseClass);
var json = new JavaScriptSerializer().Serialize(value_only);
BUT it returns [[{"data1":"a","data2":"b"},{"data1":"D","data2":"E"}]]
Is there anywasy to do it other than manually adding? Please help.
Note that {[{"data1":"a","data2":"b"},{"data1":"D","data2":"E"}]} is not valid json. In Json objects, data/values are organized by (named) properties.
However, here you seem to want a (root) Json object containing a value being Json array, but that value is not associated with a Json object property, thus not being valid Json.
If you really want invalid Json, i suggest you serialize the List<CustomModel> instance instead of the root model instance, resulting in a Json array, and then manually adding the surrounding { and } to the serialized Json string, thus giving you your desired invalid Json result:
var json = new JavaScriptSerializer().Serialize(baseClass.data);
var desiredResult = "{" + json + "}";
you don't need root class (or base class you must to deside what is name. Just use
var json = new JavaScriptSerializer().Serialize(cms);
PS.
And it is time to select a modern serializer.

Refactoring static classes and methods (Json serialisation/deserialisation)

I've used https://quicktype.io to create a class for my Json data. However I'm not really understanding why with the helper methods created to convert to json, from json, and supply default parameters they are each created differently as a static method of the class, a static class and a class with a static method.
The reason really is because as soon as I create a second class from another set of json data the code fails because of the static classes and I want to make sure I refactor them correctly. As well as understand the reasons of course.
I figure 'Converter' will never change across all my json objects so I can move this as is to a separate file and Serialize to a static method with FromJson. But I'd just like to understand more about the reasoning of how it was done in the first place and the better approach.
Here is the code:
public partial class StationDO
{
public string Active { get; set; }
//more fields here
}
public partial class StationDO
{
public static List<StationDO> FromJson(string json)
{
return JsonConvert.DeserializeObject<List<StationDO>>(json, Converter.Settings);
}
}
public static class Serialize
{
public static string ToJson(this List<StationDO> self)
{
return JsonConvert.SerializeObject(self, Converter.Settings);
}
}
public class Converter
{
public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
{
MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
DateParseHandling = DateParseHandling.None,
};
}
If I look at the Java code the same site produces, it simply puts everything bar the bean into a single class 'Converter'
You can have all the static members in StationDO class. In that case I recommend mark that class as sealed (public sealed class StationDO) to prevent someone to inheriting from that class and use the static methods from inherited class.
public class InheritedStationDO : StationDO { }
// ... somewhere else ...
InheritedStationDO.FromJson(jsonValue); // still returns List<StationDO> not List<InheritedStationDO> !!!
EDIT:
After close look I think, the whole design of members is not good.
1) There is no need to accept just List<StationDO>.
2) There is no need the defined special methods for (de)serialization of every class, you will have. You can have just one method for serialization and one for deserialization for all your classes.
Example:
public class StationDO {
public string Active { get; set; }
}
public class AnotherDO {
public string Name { get; set; }
}
// and more *DO classes
// class need to be "static" because contains "extension methods"
public static class MySerializationHelper {
private static readonly JsonSerializerSettings serializationSettings = new JsonSerializerSettings
{
MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
DateParseHandling = DateParseHandling.None,
};
// universal method for deserialization from json
// the generic type "T" represents the result type of deserialization
public static T FromJson<T>(string json) {
return JsonConvert.DeserializeObject<T>(json, serializationSettings);
}
// universal method for serialization to json
// this "this" keyword means, its "extension method"
public static string ToJson<T>(this T self) {
return JsonConvert.SerializeObject(self, serializationSettings);
}
}
Usage:
StationDO obj01 = GetSomeStation();
// returns json of one object
string json01A = obj01.ToJson(); // these two lines are equivalent
string json01B = MySerializationHelper.ToJson(obj01); // these two lines are equivalent
// returns new object deserialized from json in "json01" variable
StationDO clone01 = MySerializationHelper.FromJson<StationDO>(json01A);
StationDO obj02 = GetAnotherStation();
StationDO[] arr01 = new StationDO[] { obj01, obj02 };
// returns json of array with two objects
string json02A = arr01.ToJson(); // these two lines are equivalent
string json02B = MySerializationHelper.ToJson(arr01); // these two lines are equivalent
// returns new array with deserialized object from json in "json02" variable
StationdDO[] clone02 = MySerializationHelper.FromJson<StationdDO[]>(json02A);
AnotherDO obj03 = GetAnotherDO();
string json03A = obj03.ToJson(); // these two lines are equivalent
string json03B = MySerializationHelper.ToJson(obj03); // these two lines are equivalent
As you see, the generics is the way, how to avoid code duplication for every class.
And you can (de)serialize all kind of arrays and collections or single objects. Not just List<T>.

JSON Newtonsoft C# Good Practice for Serialize/ Deserialize Lists of Objects

I've readed others posts here about this question
Serializing a list of Object using Json.NET
Serializing a list to JSON
Merge two objects during serialization using json.net?
All very useful. Certain, I can serialize in one json two lists, but I cant deserialize it.
I´m working with Json Newtonsoft, C#, MVC5, framework 4.5. This is the scenario:
C# CODE
public class User
{
public int id { get; set; }
public string name { get; set; }
}
public class Request
{
public int id { get; set; }
public int idUSer{ get; set; }
}
List<User> UserList = new List<User>();
List<Request> RequestList = new List<Request>();
string json= JsonConvert.SerializeObject(new { UserList, RequestList });
JSON RESULT
{
"UserList":[
{
"id":1,
"name":"User 1"
},
{
"id":2,
"name":"User 2"
},
{
"id":3,
"name":"User 3"
}
],
"RequestList":[
{
"id":1,
"idUSer":1
},
{
"id":2,
"idUSer":1
},
{
"id":3,
"idUSer":1
},
{
"id":4,
"idUSer":2
}
]
}
C# DESERIALIZE
I dont Know how configure the settings of Json.Deserialize< ?, Settings>(json) for indicate what types of objects are being deserialized.
Change of approach
So that, change of approach, I've created a new class "Cover" in order to put the lists together and serialize one object
public class Cover
{
private List<User> user = new List<User>();
private List<Request> request = new List<Request>();
public List<User> User
{
get { return user;}
set { User = value;}
}
public List<Request> Request
{
get {return request;}
set {Request = value;}
}
}
SERIALIZE
string json = JsonConvert.SerializeObject(cover);
JSON The json result is the same.
DESERIALIZE
Cover result = JsonConvert.DeserializeObject<Cover>(json, new
JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto });
It's work fine. My situation is resolved but I have doubts about concepts, in my mind something is not clear:
MY QUESTIONS ARE:
For the first aproach:
Do you think that there is a way to deserialize a json with different lists of objects? Is not a good practice?
Second aproach: Why jsons are equals for first situation?
In JSON.NET you need to specify the type you're about to deserialize, by supplying its name as a type argument to DeserializeObject.
However, in this line:
string json= JsonConvert.SerializeObject(new { UserList, RequestList });
you create anonymous object and then serialize it - new { UserList, RequestList }. So there is the catch - you cannot use anonymous type as type arguments.
To handle such situations, JSON.NET provides DeserializeAnonymousType<>. It doesn't require you to supply the type argument; actually you can't as you going to deserialize anonymous type. Instead it is inferred from the type of the second argument, passed to the method. So you just create a dummy, anonymous object, without data and pass it to this method.
// jsonData contains previously serialized List<User> and List<Request>
void DeserializeUserAndRequest(string jsonData)
{
var deserializedLists = new {
UserList = new List<User>(),
RequestList = new List<Request>()
};
deserializedLists = JsonConvert.DeserializeAnonymousType(jsonData, deserializedLists);
// Do your stuff here by accessing
// deserializedLists.UserList and deserializedLists.RequestLists
}
Of course this all works fine, but this approach suggests that you already know the structure of the serialized data. If this structure doesn't match the structure of the initialized by you anonymous type you'll get nothing after the DeserializeAnonymousType method. And this is valid not just for the type of the properties of the anonymous type, but for their names too.
To your first question:
I would consider the option with the Cover class the 'best practice' as you are using the same model for serialization and deserialization and it's all up to Json.NET to figure out how to do the (de)serialization magic.
If for some reason you don't want to use this approach, there are two other options:
Anonymous types: http://www.newtonsoft.com/json/help/html/DeserializeAnonymousType.htm
Deserializing into a dictionary: http://www.newtonsoft.com/json/help/html/DeserializeDictionary.htm
To your second question - Are you sure the generated JSON is absolutely the same with both approaches? (You can use a tool like www.diffchecker .com to verify)
With your second approach the top-level names should be different - it should be 'Users' instead of 'UserList' and 'Requests' instead of 'RequestList'

C# Constructor from deserialized json?

I have a class which represent a json api. I have created a constructor that is using switched enums to select how the object is to be populated. One is for the minimum equivalent json object. Another is intended populate the properties by reading in from a file. So, I can read the file into a string and deserialize it, but what do I do next to populate the properties?
// this code is in the constructor
string text = System.IO.File.ReadAllText(fileName);
this.???? = JsonConvert.DeserializeObject<MyObject>(text); // MyObject is the object the constructor is working on
Can I cast the deserialized text into the object's properties?
Sorry for asking something that has probably already been asked, but I don't know if I am even asking the question properly (let alone searching for it). Thanks...
Not tested, but I think you could do something like this:
public MyObject(MyEnum e)
{
switch(e)
{
case MyEnum.ValueThatMeansWeDeserializeFromJSON:
string text = System.IO.File.ReadAllText(fileName);
var serializer = new JsonSerializer();
serializer.Populate(new JsonTextReader(new StringReader(text)), this);
break;
}
}
Populate will take an existing object and try to deserialize the properties from JSON into that object (as opposed to DeserializeObject which will create a new object.
As I mentioned in a comment, use a factory instead of the switch in the constructor.
If you want to keep it in the constructor use automaper and do this instead
public class MyObject
{
public MyObject()
{
}
public MyObject(Enum e)
{
string text = System.IO.File.ReadAllText(fileName);
var source = JsonConvert.DeserializeObject<MyObject>(text);
Mapper.CreateMap<MyObject, MyObject>();
Mapper.Map(source, this);
}
public string Name { get; set; }
}

Json.Net duplicates private list items

Currently I'm trying to utilize Json.Net serializer in my projects.
One of the problems that I've faced recentry is that deserialized object gets all of it's private list items duplicated.
It can be reproduced like this:
Create class with private field of List<> type, where List<> generic parameter is some other class
Add public property, that gets/sets private field
Create instance of that class, add 1 item to inner list, using property.
Serialize with new DefaultContractResolver that is setup to see private class data;
Deserialize
Code to reproduce the problem:
public class ClassParam
{
public int? ParamOne
{
get;
set;
}
}
public class ClassWithParams
{
private List<ClassParam> _privateFieid = new List<ClassParam>();
public List<ClassParam> PropertWithBackingField
{
get { return _privateFieid; }
set { _privateFieid = value; }
}
public void AddElementToPrivateField(ClassParam classParam)
{
_privateFieid.Add(classParam);
}
}
[Test]
public void Test()
{
var instance = new ClassWithParams();
var param1 = new ClassParam { ParamOne = 1 };
instance.PropertWithBackingField.Add(param1);
var contractResolver = new DefaultContractResolver();
contractResolver.DefaultMembersSearchFlags |= BindingFlags.NonPublic;
string serializedInstance = JsonConvert.SerializeObject(instance,
Formatting.Indented,
new JsonSerializerSettings()
{
ContractResolver = contractResolver
});
var deserializeInstance = JsonConvert.DeserializeObject(serializedInstance, typeof(ClassWithParams),
new JsonSerializerSettings()
{
ContractResolver = contractResolver
});
}
When I remove public property PropertWithBackingField from ClassWithParams it's all ok.
The problem is gone as well when I don't use custom setup for ContractResolver. But I do need to serialize private data of my classes as soon as not all of it is exposed via public properties.
What's wrong with my code? Are there any subtleties, using Json.Net or is it a bug?
For this code
var s = JsonConvert.SerializeObject(instance);
var desInst = JsonConvert.DeserializeObject<ClassWithParams>(s);
Your json will be {"PropertWithBackingField":[{"ParamOne":1}]}
But you say to include private field in serialization/deserialization with
contractResolver.DefaultMembersSearchFlags |= BindingFlags.NonPublic;
and get a json
{
"_privateFieid": [
{
"ParamOne": 1
}
],
"PropertWithBackingField": [
{
"ParamOne": 1
}
]
}
So there are two deserializations, one for _privateFieid and one for PropertWithBackingField
Either use BindingFlags.Public or use my code above with is much simpler.
DeserializeInstance method receives existing instance as argument. Probably it does not creates new instance but fills in existing and returns it.
Try to put ReferenceEquals(instance, deserializedInstance) to your watch. To avoid data duplicating use overload that does not accepts existing instance or create new instance and deserialize it.

Categories