I am having some trouble deserializing an object to XML. I am trying to deserialize something which doesn't have an empty constructor thus I need to use the BinaryFormatter? I have:
A DLL which consists of a class I want to deserialize into XML.
From reflecting the type I can see that it has no parameterless constructor.
This class contains properties of which some do not have empty constructors either.
My question is, is it possible to deserialize this class into XML? I did find a way whereby I used:
BinaryFormatter
Loaded the contents into a stream
Used a FileStream to write its contents but ended up with rubbish
Thanks in advance. I found something called FormatterServices... but don't know whether you could use this in conjunction with the XmlSerializer?
Deserialize the binary data back into an object.
Copy your object into a surrogate object.
Xml serialize your surrogate object.
Assume the type of your original non-xml serializable object is "Foo"
[XmlRoot]
public class FooSurrogate {
public FooSurrogate() { }; // note the empty constructor for xml deserialization
public FooSurrogate(Foo foo) { // this constructor is used in step 2
// in here you copy foo's state into this object's state
this.Prop1 = foo.Prop1; // this prop can be copied directly
this.Bar = new BarSurrogate(foo.Bar); // this prop needs a surrogate as well
}
[XmlAttribute] // note your surrogate can be used to xml-format too!
public string Prop1 { get; set; }
[XmlElement]
public BarSurrogate Bar { get; set; }
}
public class BarSurrogate {
...
}
Related
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.
I Use JsonConvert to serialize an object and save it in a database. This is a sample of the serialized string that I saved in database:
[{"matId":"1","value":"44"},{"matId":"2","value":"55"},{"matId":"4","value":"77"}]
Now when I get this string from database which has a lot of backslashes like this:
"[{\"matId\":\"1\",\"value\":\"44\"},{\"matId\":\"2\",\"value\":\"55\"},{\"matId\":\"4\",\"value\":\"77\"}]"
And for this reason I can't Deserialize it.
.Replace("\\","") method doesn't create any affect on this. I don't know why.
You have to use JsonConvert.Deserialize method.
Your json string is wrapped within square brackets ([]), hence it is interpreted as array. Therefore, you need to deserialize it to type collection of one class, for example let's call it MyClass.
public class MyClass
{
public int matId { get; set; }
public int value { get; set; }
}
Here is Deserialize method.
var results=JsonConvert.DeserializeObject<List<MyClass>>(json);
Backslashes represent serialized object.
You need to deserialize your List object.
You can try using Generics:
public List<T> Deserialize<T>(string path)
{
return JsonConvert.DeserializeObject<List<T>>(path);
}
Be careful when looking at json strings as you are debugging. In Visual Studio it needs to format the value into a string. To do that it will add " so that it can process it when actually the value does not contain them. That is why the replace does not work.
I am attempting to save/load a class to an xml file that contains generic types using a DataContractSerializer. I have the save working, but have realized I can't load it because I don't have the list of knownTypes for the deserializer.
Is there a way of serializing/deserializing this class that would allow me to deserialize it without referencing any of the stored types directly?
Here is my SessionVariables class that I am trying to save/load:
[DataContract]
public class SessionVariables
{
[DataMember]
private Dictionary<Type, ISessionVariables> _sessionVariables = new Dictionary<Type, ISessionVariables>();
private object _syncLock = new object();
public T Get<T>()
where T : ISessionVariables, new()
{
lock (_syncLock)
{
ISessionVariables vars = null;
if (_sessionVariables.TryGetValue(typeof(T), out vars))
return (T)vars;
vars = new T();
_sessionVariables.Add(typeof(T), vars);
return (T)vars;
}
}
public IList<Type> GetKnownTypes()
{
IList<Type> knownTypes = new List<Type>();
knownTypes.Add(this.GetType().GetType()); // adds System.RuntimeType
foreach (Type t in _sessionVariables.Keys)
{
if (!knownTypes.Contains(t))
knownTypes.Add(t);
}
return knownTypes;
}
}
The different modules of the application extend the ISessionVariables interface to create their own set of session variables, like this:
[DataContract]
public class ModuleASessionVariables : ISessionVariables
{
[DataMember]
public string ModuleA_Property1{ get; set; }
[DataMember]
public string ModuleA_Property2 { get; set; }
}
[DataContract]
public class ModuleBSessionVariables : ISessionVariables
{
[DataMember]
public string ModuleB_Property1{ get; set; }
[DataMember]
public string ModuleB_Property2 { get; set; }
}
And a singleton instance of the SessionVariables class is used to access session variables, like this:
singletonSessionVariables.Get<ModuleASessionVariables>().ModuleA_Property1
singletonSessionVariables.Get<ModuleBSessionVariables>().ModuleB_Property2
I got the save working like this:
using (FileStream writer = new FileStream(#"C:\test.txt", FileMode.Create))
{
DataContractSerializer dcs = new DataContractSerializer(typeof(SessionVariables), singletonSessionVariables.GetKnownTypes());
dcs.WriteObject(writer, singletonSessionVariables);
writer.Close();
}
However this method does not work to deserialize the class because I don't know it's known types.
Can I serialize and deserialize generic types when I don't have direct library references to any of the types used? And if so, how?
The problem here is that you aren't just wanting to serialize data, but you also want to serialize data about your data, i.e., (cue the dramatic chipmunk) metadata.
That metadata, in this case, are the types of the models that held the data originally. Normally, this isn't an issue, but as you've discovered if you're taking advantage of polymorphism in your design, your single collection may contain two or more different types, each of which needs to be deserialized to their original type.
This is usually accomplished by saving this Type metadata to the serialized result. Different serialization methods does this in different ways. Xaml serialization uses xml namespaces associated with .net namespaces, then names the elements after the original type name. Json.net accomplishes this via a specific named value saved to the json object.
The default DataContractSerializer is not Type aware. Therefore you need to replace it with a version that understands the .NET Type system and can serialize/deserialize Type metadata to the resulting xml. Luckily, one already exists in the framework, the NetDataContractSerializer.
And that's how you pad a link-only answer. The Aristocrats.
You could accomplish this using a custom DataContractResolver. This allows you to plug into the deserialization pipeline and provide a type to deserialize into based upon the type/namespace that is found in the serialized graph.
Here's a good article on it:
http://blogs.msdn.com/b/carlosfigueira/archive/2011/09/21/wcf-extensibility-data-contract-resolver.aspx
IDesign has an implementation of a resolver that can be used for dynamic discovery of types on their site: http://idesign.net/Downloads/GetDownload/1848 (you will probably have to make some modifications to handle generics)
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.
I need to deserialize some JavaScript object represented in JSON to an appropriate C# class. Given the nice features of automatic properties, I would prefer having them in these classes as opposed to just having fields. Unfortunately, the .NET serialization engine (at least, by default) totally ignores automatic properties on deserialization and only cares about the backing field, which is obviously not present in the JavaScript object.
Given that there's no standard way to name backing fields and to be honest I don't even want to bother with the "let's create a JavaScript object that looks like it had C# backing fields" approach as it sounds a bit dirty, the only way I could serialize JavaScript fields to C# auto-properties if I could force the serialization engine to somehow ignore the backing field and use the property directly. Unfortunately, I can't figure out how this is done or if this can be done at all. Any ideas would be appreciated.
EDIT: Here's an example:
Javascript:
function Cat()
{
this.Name = "Whiskers";
this.Breed = "Tabby";
}
var cat = new Cat();
This is then serialized to "{Name: 'Whiskers'}".
The C# class:
[Serializable()]
public class Cat
{
public string Name { get; set; }
public string Breed { get; set; }
}
And the deserialization code, that fails:
new DataContractJsonSerializer(typeof(Cat)).ReadObject(inputStream);
And it is apparent from the exception that it fails because it is looking for the backing field.
EDIT2: Here's the exception, if that helps (no inner exceptions):
System.Runtime.Serialization.SerializationException
"The data contract type 'Test.Cat'
cannot be deserialized because the
required data members
'<Name>k__BackingField, <Breed>k__BackingField' were not
found."
What's happening here is the deserializer is trying to guess the name of your backing fields.
You can solve this by adding explicit mappings (DataContract/DataMember attributes) like this:
[DataContract]
public class Cat
{
[DataMember]
public string Name { get; set; }
[DataMember]
public string Breed { get; set; }
}
You can do this with JavaScriptSerializer found in the System.Web.Script.Serialization namespace:
JavaScriptSerializer serializer = new JavaScriptSerializer();
Cat c = serializer.Deserialize<Cat>(jsonString);
I have POCO objects with automatic properties and this works just fine.
EDIT: I wrote about JSON Serializers in .NET which compares this serializer with DataContractJsonSerializer.
baretta's answer solved the k__BackingField bloat for me. Just a tiny addendum that you can decorate this class to auto serialize into either XML or JSON in a similar way:
[Serializable, XmlRoot, DataContract]
public class Cat
{
[XmlElement]
[DataMember]
public string Name { get; set; }
[XmlElement]
[DataMember]
public string Breed { get; set; }
}
... and then use a DataContractJsonSerializer or XmlSerializer to prepare it for your endpoint.
I'm assuming you are passing data via a web service. If you are using the WebService class with the ScriptMethod attribute uncommented-out, the web service methods can read JSON natively. They even use the same JavaScriptSerializer that was mentioned above. If you are using WCF I'm a little more fuzzy on the logic.
But make sure your JSON object are returning data for EVERY property in your class. In your error, there is mention of a Breed property that is not in your example.
Also, on the JavaScript side, do to the dynamic nature of JavaScript it is easy to add new properties to your objects. This can sometimes lead to circular references. You should remove any extra data that you might have added (just as you are sending data via the web method, then add it again once you are done).