Discover output class from json.net - c#

I'm doing a project where I dynamically build a set of objects based on reflection and serialize it (using json.net).
What I want to do is to deserialize it and recreate the object tree, but I don't know the final class type.
So how can I find out?
Here's an example:
public class insideBleah
{
public int BProperty
{ get; set; }
}
public class bleah
{
public int AProperty
{ get; set; }
public insideBleah Inside
{ get; set; }
}
and
var bleah = new bleah();
bleah.AProperty = 1;
bleah.Inside = new insideBleah();
bleah.Inside.BProperty = 2;
var output = JsonConvert.SerializeObject(bleah, new JsonSerializerSettings()
{
TypeNameHandling = TypeNameHandling.Objects
});
This produces the output string:
"{\"$type\":\"jsontest.bleah, jsontest\",\"AProperty\":1,\"Inside\":{\"$type\":\"jsontest.insideBleah, jsontest\",\"BProperty\":2}}"
So I can see the class in there. It's so close! But I can't seem to tease the information out.
How can I do this? I can't do:
var newObject = (bleah)JsonConvert.DeserializeObject<bleah>(output);
because I don't know it's a 'bleah'.
How can I handle this?
Thanks in advance

Why can you just use:
using System;
using Newtonsoft.Json;
namespace ConsoleApplication1
{
class Program
{
private static void Main(string[] args)
{
var bleah = new Person();
var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Objects };
var output = JsonConvert.SerializeObject(bleah, settings);
Console.WriteLine(output);
var deserializeObject = JsonConvert.DeserializeObject(output, settings);
Console.WriteLine(deserializeObject.GetType().Name);
}
}
class Person
{
public string Name { get; set; }
}
}
The output:
{"$type":"ConsoleApplication1.Person, ConsoleApplication1","Name":null}
Person

Related

Data loss when serializing with JSON

This is the code that reproduces the problem:
internal class Program
{
private static JsonSerializerSettings Setting = new Newtonsoft.Json.JsonSerializerSettings()
{
PreserveReferencesHandling = PreserveReferencesHandling.Objects,
};
static void Main(string[] args)
{
var script = new SubClass();
script.Param.Add(new Parameter()
{
msg = "I will die"
});
var obj = new Class();
obj.subObj = script;
string json;
string json2;
json = JsonConvert.SerializeObject(obj, Setting);
Console.WriteLine("before:");
Console.WriteLine(json);
obj = Newtonsoft.Json.JsonConvert.DeserializeObject<Class>(json, Setting);
json2 = JsonConvert.SerializeObject(obj, Setting);
Console.WriteLine("after:");
Console.WriteLine(json2);
}
public class Class
{
public IEnumerable<Parameter> parameters => subObj?.parameters();
public SubClass subObj { get; set; }
}
public class Parameter
{
public string msg { get; set; }
}
public class SubClass
{
public List<Parameter> Param { get; set; } = new List<Parameter>();
public IEnumerable<Parameter> parameters()
{
return Param;
}
}
}
The results of this run show that the results of the two serializations are different:
before:
{"$id":"1","parameters":[{"$id":"2","msg":"I will die"}],"subObj":{"$id":"3","Param":[{"$ref":"2"}]}}
after:
{"$id":"1","parameters":[null],"subObj":{"$id":"2","Param":[null]}}
I tried to delete the Class.parameters attribute, and the running results returned to normal. I don't understand why?
i've tried your code and here what I found.
If you delete
PreserveReferencesHandling = PreserveReferencesHandling.Objects,
the code workk just fine.
I think it's a problem of setter because if you put a break point you can see that the problem is cause by the deserialisation.
I know by experience that newtonsoft is tricky with some setter and if they are in private they're unable to be use by it.
I hope that help you

De-/serialization with a list of objects

I try to save and read multiple objects in one XML-File.
The function Serialize is not working with my existing List, but i dont know why. I already tried to compile it but i get an error wich says, that the methode needs an object refference.
Program.cs:
class Program
{
static void Main(string[] args)
{
List<Cocktail> lstCocktails = new List<Cocktail>();
listCocktails.AddRange(new Cocktail[]
{
new Cocktail(1,"Test",true,true,
new Cocktail(1, "Test4", true, true, 0)
});
Serialize(lstCocktails);
}
public void Serialize(List<Cocktail> list)
{
XmlSerializer serializer = new XmlSerializer(typeof(List<Cocktail>));
using (TextWriter writer = new StreamWriter(#"C:\Users\user\Desktop\MapSample\bin\Debug\ListCocktail.xml"))
{
serializer.Serialize(writer, list);
}
}
private void DiserializeFunc()
{
var myDeserializer = new XmlSerializer(typeof(List<Cocktail>));
using (var myFileStream = new FileStream(#"C:\Users\user\Desktop\MapSample\bin\Debug\ListCocktail.xml", FileMode.Open))
{
ListCocktails = (List<Cocktail>)myDeserializer.Deserialize(myFileStream);
}
}
Cocktail.cs:
[Serializable()]
[XmlRoot("locations")]
public class Cocktail
{
[XmlElement("id")]
public int CocktailID { get; set; }
[XmlElement("name")]
public string CocktailName { get; set; }
[XmlElement("alc")]
public bool alcohol { get; set; }
[XmlElement("visible")]
public bool is_visible { get; set; }
[XmlElement("counter")]
public int counter { get; set; }
private XmlSerializer ser;
public Cocktail() {
ser = new XmlSerializer(this.GetType());
}
public Cocktail(int id, string name, bool alc,bool vis,int count)
{
this.CocktailID = id;
this.CocktailName = name;
this.alcohol = alc;
this.is_visible = vis;
this.counter = count;
}
}
}
Ii also think I messed something up with the DiserializeFunc().
You are very close to implementing the Cocktail class correctly, but I think you're confused about how to serialize Lists. Your implementation of a Cocktail object class is completely fine, just get rid of the list related functions.
using System;
using System.Xml.Serialization;
namespace Serialization_Help
{
[Serializable()]
[XmlRoot("locations")]
public class Cocktail
{
[XmlElement("id")]
public int CocktailID { get; set; }
[XmlElement("name")]
public string CocktailName { get; set; }
[XmlElement("alc")]
public bool alcohol { get; set; }
[XmlElement("visible")]
public bool is_visible { get; set; }
[XmlElement("counter")]
public int counter { get; set; }
public Cocktail() {
}
public Cocktail(int id, string name, bool alc, bool vis, int count)
{
this.CocktailID = id;
this.CocktailName = name;
this.alcohol = alc;
this.is_visible = vis;
this.counter = count;
}
}
}
Now in your new function you want to serialize the list directly.
using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;
namespace Serialization_Help
{
class Program {
static void Main(string[] args) {
List<Cocktail> list = new List<Cocktail> {
new Cocktail(01, "rum and coke", true, true, 5),
new Cocktail(02, "water on the rocks", false, true, 3)
};
Serialize(list);
List<Cocktail> deserialized = DiserializeFunc();
}
public static void Serialize(List<Cocktail> list) {
XmlSerializer serializer = new XmlSerializer(typeof(List<Cocktail>));
using (TextWriter writer = new StreamWriter(Directory.GetCurrentDirectory() + #"\ListCocktail.xml")) serializer.Serialize(writer, list);
}
private static List<Cocktail> DiserializeFunc() {
var myDeserializer = new XmlSerializer(typeof(List<Cocktail>));
using (var myFileStream = new FileStream(Directory.GetCurrentDirectory() + #"\ListCocktail.xml", FileMode.Open)) return (List<Cocktail>)myDeserializer.Deserialize(myFileStream);
}
}
}
Doing so should correctly print out the following .xml output:
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfCocktail xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Cocktail>
<id>1</id>
<name>rum and coke</name>
<alc>true</alc>
<visible>true</visible>
<counter>5</counter>
</Cocktail>
<Cocktail>
<id>2</id>
<name>water on the rocks</name>
<alc>false</alc>
<visible>true</visible>
<counter>3</counter>
</Cocktail>
</ArrayOfCocktail>
Keep in mind that I have not provided implementation of any of the standard safety or null checks for the file. You'll have to check if the file exists yourself by using File.Exists(...) (see here for File.Exists implementation) and implement the correct try and catch cases and what your code will chose to do if it runs into serialization or input/outut errors.
You'd better use ExtendedXmlSerializer to serialize and deserialize.
Instalation
You can install ExtendedXmlSerializer from nuget or run the following command:
Install-Package ExtendedXmlSerializer
Serialization:
ExtendedXmlSerializer serializer = new ExtendedXmlSerializer();
var list = new List<Cocktail>();
var xml = serializer.Serialize(list);
Deserialization
var list = serializer.Deserialize<List<Cocktail>>(xml);
Standard XML Serializer in .NET is very limited.
Does not support serialization of class with circular reference or class with interface property,
Does not support Dictionaries,
There is no mechanism for reading the old version of XML,
If you want create custom serializer, your class must inherit from IXmlSerializable. This means that your class will not be a POCO class,
Does not support IoC.
ExtendedXmlSerializer can do this and much more.
ExtendedXmlSerializer support .NET 4.5 or higher and .NET Core. You can integrate it with WebApi and AspCore.

Deserialize part of a binary file

Is it possible to deserialize part of a binary file?
Basically I have an object similar to below, which I serialize into a binary file.
public class MyObject
{
public string Name { get; set; }
public int Value { get; set; }
public IList<MyOtherObject> { get; set; } // lots of data in here (order of kB-MB)
}
What I would like is to be able to deserialize only Name and Value by way of populating a ListView for file selection purposes and then deserialize the rest of the file when needed (i.e. the user chooses that file from the ListView).
As always, any help greatly appreciated and if any 3rd party libraries are suggested they would need to be able to be used freely in a commercial environment.
protobuf-net can do that, because it is not tied to the specific type; for example:
using ProtoBuf;
using System.Collections.Generic;
using System.IO;
[ProtoContract]
public class MyOtherObject { }
[ProtoContract]
public class MyObject
{
[ProtoMember(1)]
public string Name { get; set; }
[ProtoMember(2)]
public int Value { get; set; }
[ProtoMember(3)]
public IList<MyOtherObject> Items { get; set; }
}
[ProtoContract]
public class MyObjectLite
{
[ProtoMember(1)]
public string Name { get; set; }
[ProtoMember(2)]
public int Value { get; set; }
}
static class Program
{
static void Main()
{
var obj = new MyObject
{
Name = "abc",
Value = 123,
Items = new List<MyOtherObject>
{
new MyOtherObject(),
new MyOtherObject(),
new MyOtherObject(),
new MyOtherObject(),
}
};
using (var file = File.Create("foo.bin"))
{
Serializer.Serialize(file, obj);
}
MyObjectLite lite;
using (var file = File.OpenRead("foo.bin"))
{
lite= Serializer.Deserialize<MyObjectLite>(file);
}
}
}
But if you don't want two different types, and/or you don't want to have to add attributes - that can be done too:
using ProtoBuf.Meta;
using System.Collections.Generic;
using System.IO;
public class MyOtherObject { }
public class MyObject
{
public string Name { get; set; }
public int Value { get; set; }
public IList<MyOtherObject> Items { get; set; }
}
static class Program
{
static readonly RuntimeTypeModel fatModel, liteModel;
static Program()
{
// configure models
fatModel = TypeModel.Create();
fatModel.Add(typeof(MyOtherObject), false);
fatModel.Add(typeof(MyObject), false).Add("Name", "Value", "Items");
liteModel = TypeModel.Create();
liteModel.Add(typeof(MyOtherObject), false);
liteModel.Add(typeof(MyObject), false).Add("Name", "Value");
}
static void Main()
{
var obj = new MyObject
{
Name = "abc",
Value = 123,
Items = new List<MyOtherObject>
{
new MyOtherObject(),
new MyOtherObject(),
new MyOtherObject(),
new MyOtherObject(),
}
};
using (var file = File.Create("foo.bin"))
{
fatModel.Serialize(file, obj);
}
MyObject lite;
using (var file = File.OpenRead("foo.bin"))
{
lite = (MyObject)liteModel.Deserialize(
file, null, typeof(MyObject));
}
}
}
How about putting the Name and Valueinto a superclass and serializing them separately?
Alternatively, you could maintain a Dictionary and serialize that into one file.

using generics with xml deserialisation

I want to pass an object into the resulting type of an xml deserialisation and maintain strong typing.
So the deserialisation class can take any type that implements the IResult interface which in this case is Result and Result2.
I have got this working by making the getObject method return dynamic but i would much rather keep the compile time checking and i think it should be possible.
I have tried using generics, as in the example below, but the deser.getObject(doc()); line gives me a "cannot be inferred from usage" compile error.
Thanks for all help.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
namespace SOQuestion
{
class Program
{
static void Main(string[] args)
{
var deser = new Deserialised(new Result());
var result = deser.getObject(doc());
var deser2 = new Deserialised(new Result2());
var result2 = deser.getObject(doc());
Console.Writeline(result.status);
Console.Writeline(result2.status);
}
public XmlDocument doc()
{
var doc = new XmlDocument();
var el = (XmlElement)doc.AppendChild(doc.CreateElement("Result"));
el.SetAttribute("status", "ok");
el.SetAttribute("status2", "not ok");
return doc;
}
}
class Deserialised
{
private IResult result;
private Type resultType;
public Deserialised(IResult _result)
{
result = _result;
resultType = Type.GetType(result.GetType().AssemblyQualifiedName);
}
public T getObject<T>(XmlDocument xml)
{
var mySerializer = new XmlSerializer(resultType);
var myStream = new MemoryStream();
xml.Save(myStream);
myStream.Position = 0;
var r = mySerializer.Deserialize(myStream);
return (T)r;
}
}
interface IResult
{
public string status {get;set;}
}
[Serializable]
public class Result :IResult
{
[XmlAttribute]
public string status { get; set; }
}
[Serializable]
public class Result2 : IResult
{
[XmlAttribute]
public string status2 { get; set; }
}
}
Indeed, that isn't going to work - the compiler has no way of knowing the T from that. Remember that the T comes from the caller at compile-time, not from the result of the method at runtime. There are ways to switch between reflection/generics, but it is ugly and isn't going to help much here. I would just return object instead:
public object GetObject(XmlDocument xml) {
var mySerializer = new XmlSerializer(resultType);
using(var myStream = new MemoryStream()) {
xml.Save(myStream);
myStream.Position = 0;
return mySerializer.Deserialize(myStream);
}
}
and then let the caller handle the dynamic etc:
var deser = new Deserialised(new Result());
dynamic result = deser.GetObject(doc());
var deser2 = new Deserialised(new Result2());
dynamic result2 = deser.GetObject(doc());
Console.Writeline(result.status);
Console.Writeline(result2.status);
Because of the dynamic above, the .status in the two Console.WriteLine will still work.
In my opinion the answer you provided yourself overcomplicates things. (In addition to doing some other weird stuff, ... see my comment.)
There is nothing gained in using generics here. You can just as well use the following approach, and both of your requirements will still hold.
public IResult GetObject(XmlDocument xml)
{
var mySerializer = new XmlSerializer(resultType);
using (var myStream = new MemoryStream())
{
xml.Save(myStream);
myStream.Position = 0;
return (IResult)mySerializer.Deserialize(myStream);
}
}
... simply call it as follows:
var deser = new Deserialised(new Result());
var result = (Result)deser.getObject(doc());
var deser2 = new Deserialised(new Result2());
var result2 = (Result2)deser.getObject(doc());
Casting to anything which doesn't implement IResult will trigger a compiler error.
It is not really clear what you are trying to do here, but suppose you made Deserialised generic.
class Deserialised<T>
where T : IResult
{
private T result;
private Type resultType;
public Deserialised(T _result)
{
result = _result;
}
public T getObject(XmlDocument xml)
{
var mySerializer = new XmlSerializer(typeof(T));
var myStream = new MemoryStream();
xml.Save(myStream);
myStream.Position = 0;
var r = (T)mySerializer.Deserialize(myStream);
return r;
}
}
Why are you even passing _result as a parameter and storing it? My guess is you only needed it since you didn't know about typeof()? In that case simply drop it. After doing so again you just end up with a class which defines your generic parameter, with again the sole purpose to define the required cast.
So i have found a solution that my two requirements of 1. that passed in type implements IResult interface 2. that the returned object is statically typed.
A generic method with a constraint like below
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
namespace SOQuestion
{
class Program
{
static void Main(string[] args)
{
var result = new Deserialised().getObject<Result>();
var result2 = new Deserialised().getObject<Result2>();
Console.WriteLine(result.status);
Console.WriteLine(result.errorMessage);
Console.ReadLine();
}
}
class Deserialised
{
public T getObject<T>() where T : IResult
{
try
{
var instance = Activator.CreateInstance<T>();
var mySerializer = new XmlSerializer(instance.GetType());
var myStream = new MemoryStream();
doc().Save(myStream);
myStream.Position = 0;
var r = mySerializer.Deserialize(myStream);
throw new DivideByZeroException();
return (T)r;
}
catch (Exception exp)
{
var instance = Activator.CreateInstance<T>();
instance.errorMessage = "something wrong here";
return instance;
}
;
}
public static XmlDocument doc()
{
var doc = new XmlDocument();
var el = (XmlElement)doc.AppendChild(doc.CreateElement("Result"));
el.SetAttribute("status", "ok");
el.SetAttribute("status2", "notok");
return doc;
}
}
interface IResult
{
string status { get; set; }
string errorMessage { get; set; }
}
[Serializable]
public class Result : IResult
{
[XmlAttribute]
public string status { get; set; }
[XmlAttribute]
public string errorMessage { get; set; }
[XmlAttribute]
public string message { get; set; }
}
[Serializable]
public class Result2 : IResult
{
[XmlAttribute]
public string status { get; set; }
[XmlAttribute]
public string message2 { get; set; }
[XmlAttribute]
public string errorMessage { get; set; }
}
[Serializable]
public class Result3
{
[XmlAttribute]
public string status { get; set; }
[XmlAttribute]
public string message2 { get; set; }
[XmlAttribute]
public string errorMessage { get; set; }
}
}

Json Deserialization to a class

I have dynamic json result and i want to create an object for that json string. After that i will fill that object with the deserialized object. Here is the json string:
[{"_34":{
"Id":"34",
"Z":["42b23718-bbb8-416e-9241-538ff54c28c9","c25ef97a-89a5-4ed7-89c7-9c6a17c2413b"],
"C":[]
}
}]
How does the object look like? Or how can i deserialize this string to a class.
Thanks.
You can use the JavaScriptSerializer which available out of the box or json.net if you prefer something open source.
Based on Darin Dimitrov's sample, here's how you'd do with json.net:
using System.Collections.Generic;
using System;
using Newtonsoft.Json;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string json = "[{\"_34\":{ \"Id\":\"34\", \"Z\":[\"42b23718-bbb8-416e-9241-538ff54c28c9\",\"c25ef97a-89a5-4ed7-89c7-9c6a17c2413b\"], \"C\":[] } }]";
var result = JsonConvert.DeserializeObject<Dictionary<string, Result>[]>(json);
Console.WriteLine(result[0]["_34"].Z[1]);
}
}
public class Result
{
public string Id { get; set; }
public string[] Z { get; set; }
public string[] C { get; set; }
}
}
Here's an example:
using System;
using System.Collections.Generic;
using System.IO;
using System.Web.Script.Serialization;
public class Result
{
public string Id { get; set; }
public string[] Z { get; set; }
public string[] C { get; set; }
}
class Program
{
static void Main()
{
var json = #"[{""_34"": {""Id"": ""34"",""Z"": [""42b23718-bbb8-416e-9241-538ff54c28c9"",""c25ef97a-89a5-4ed7-89c7-9c6a17c2413b""],""C"": []}}]";
var serializer = new JavaScriptSerializer();
var result = serializer.Deserialize<Dictionary<string, Result>[]>(json);
Console.WriteLine(result[0]["_34"].Z[1]);
}
}
Target class
public class Target
{
public string Id;
public List<string> Z;
public List<string> C;
}
Deserialization
var ser = new JavaScriptSerializer();
var obj = ser.Deserialize<Target>(json);
Wrap your string in eval function:
var myObject = eval('(' + myJSONtext + ')');

Categories

Resources