C# automatic property deserialization of JSON - c#

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).

Related

C# XML Deserialize ignore Default value attribute

I am having a class with a set of properties that I use as user level settings. Each property has a Default Value attribute. Few has XmlIgnore attribute to avoid the serialization.
When serializing this class object as memory stream and it writes it correct, but while de-serializing it actually creates an object with all the properties default value which was not part of the serialized object. How can I ignore this default value initialization for few properties? Thanks in advance.
XmlSerializer serializer = new mlSerializer(typeof(DisplayPreferences));
DisplayPreferences newPrefs = null;
MemoryStream ms = new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(prefs));
newPrefs = (DisplayPreferences)serializer.Deserialize(ms);
if (newPrefs != null)
{
newPrefs.CopyTo(Editor.prefs);
}
This app is built in .NET 4.6 (winforms)
Welcome to stackoverflow.
You've given very little information on how you are de-serializing them (a code snippet would help), but I assume you are de-serializing them into a typed object. If that is the case, then what you are experiencing is standard behavior. That is the whole point of the default value, you can't "partially de-serialize a typed object".
What you can do however is either:
de-serializing the object into a raw xmlObject, and write a custom serializer for it.
Make the properties nullable, this is typically where DTO's are useful.See below.
public class SomeTypedObjectDTO
{
public Guid? NullableGuid { get; set; }
public int? NullableInt { get; set; }
}
----UPDATE----
I tired to keep this in line with your code. Lets say you have the following object.
public class DisplayPreferences
{
public Guid Id { get; set; }
public string Name { get; set; }
public int Level { get; set; }
public bool CanDisplay { get; set; }
}
And lets say you only want to serialize the "CanDisplay" and the "level" properties. You can create a DTO (Data Transfer object) for it, which is basically a stripped down version of the original object.
DTO:
public class DisplayPreferencesDTO
{
public int Level { get; set; }
public bool CanDisplay { get; set; }
}
Then I believe all you need to do is change the generic typeof() to use the DTO instead of the actual object.
XmlSerializer serializer = new mlSerializer(typeof(DisplayPreferencesDTO));
You can then map the DTO back to the original object when you like and if you like. You can either do this mapping manually or use a framework called Automapper. Automapper was explicitly designed for mapping DTO's.
If you need me to clarify anything let me know.
Happy coding!
You may want to make them as null? just make them to nullable prop
such as make a int to int?

Parse json object with another json object in string format stored in one of the properties

I think I have quite a unique problem here, where the developer of an API I need to utilize did something I don't quite understand. Yet I have to deal with it.
It is probably the best to explain the problem by showing an example:
{
"type": "type-A",
"value": "{'propA': 'type-A specific element', 'propA2': 'another typeA specific element'}"
}
We are dealing with a quite normal REST API, where the response is a json string - nothing too special. Because of some abstraction going on within the API, there is a type and a value field in each response. Depending on the type, the value will have differently structured content. Also nothing too special.
The problem is now that the content in the value field is not just a normal json object, but a string containing a json object. Therefore deserialization with JsonConvert.DeserializeObject<TargetType>(jsonString) fails with the exception
Newtonsoft.Json.JsonSerializationException: Error converting value
"{'propA': 'type-A specific element', 'propA2': 'another typeA
specific element'}" to type 'My.Project.TargetType'.
Is there any neat built-in support in the json.net library I might use to counter this issue or do I have to go a manual route and fix the json or the deserialization in some other way?
Edit: to give a bit more context: The API does indeed try to abstract its interface with equal requests and responses, but I am still able to request very specific responses in my code. Therefore I make use of a generic class which contains the common properties and a generic type for the value like so:
public class Response<TValue>
{
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("value")]
public TValue Value { get; set; }
}
In fact, the type isn't even relevant for me, because I know beforehand which type I will receive as response (due to my specific request). Therefore I am also able to determine the response type of value. My actual deserialization looks like this JsonConvert.DeserializeObject<Response<TargetType>>(jsonString).
Yet I did not find a neat way of parsing my value together with the Response object. Any suggestions are highly appreciated.
No, in your case you just need two steps:
public class RootObject
{
public string type {get;set;}
public string value {get;set;}
}
RootObject r = JsonConvert.DeserializeObject<RootObject>(json);
And then, depending on the type, deserialize the other object:
if (r.type == "typeA")
{
TypeA t = JsonConvert.DeserializeObject<TypeA>(r.value);
}
If all types share some common properties, you might put them in an interface or base class. This will also ease reusing the deserialized class.
I solved the problem myself by using a built-in which calls a method after deserialization of the object itself.
public class Response<TValue>
{
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("value")]
private string ValueString { get; set; }
public TValue Value { get; set; }
[OnDeserialized]
internal void DeserializeValue(StreamingContext context)
{
Value = JsonConvert.DeserializeObject<TValue>(ValueString);
}
}
This allows me to simply call JsonConvert.DeserializeObject<Response<TargetType>>(json), where it will first deserialize the Response and after that the value property will be deserialized to TargetType.

Control the XML generated for automatic properties

Can anyone explain how to control the XML generated ?
I have a simple test class, NumberService ...
[Serializable]
public class NumberService
{
public int Number1 { get; set; }
public int Number2 { get; set; }
}
Now if I use an XmlSerializer to deserialise an instance, I get what I expected ...
<NumberService>
<Number1>23</Number1>
<Number2>45</Number2>
</NumberService>
but I was attempting to send this and Fiddler was showing ...
<NumberService>
<_x003C_Number1_x003E_k__BackingField>10</_x003C_Number1_x003E_k__BackingField>
<_x003C_Number2_x003E_k__BackingField>2</_x003C_Number2_x003E_k__BackingField>
</NumberService>
Poking around I've read that this is because of my use of automatic properties, and indeed if I changed to ...
public class NumberService
{
private int _number1;
public int Number1
{
get { return _number1; }
set { _number1 = value; }
}
public int Number2 { get; set; }
}
indeed the XML changes to ...
<NumberService>
<_number1>4</_number1>
<_x003C_Number2_x003E_k__BackingField>6</_x003C_Number2_x003E_k__BackingField>
</NumberService>
But of course I can't change _number1 to Number1 as it'd conflict with the property :-(
So how can you control the XML ?
... and a bit more reading ...
this is involving WCF data contracts
This has to do with how the DataContractSerializer handles items with the Serializable attribute applied.
When confronted with the Serializable attribute, the DataContractSerializer will defer to the semantics that you would expect when using the instance with an IFormatter implementation; in other words, it will serialize the underlying fields using the names of the fields as the keys to the data.
Because you are using auto-generated properties, what you are seeing is actually the names of the auto-generated fields that the compiler generates for you.
In order to get around this, you should apply the DataContract attribute to the class and the DataMember attribute to the properties (and you can control the name by specifying it in the attribute if you want it to differ from the property name).
You also have the option of not specifying the DataContract/DataMember attributes at all and using POCO DataContract serialization; this assumes you have a default parameterless constructor along with only serializing public properties/fields.
You should remove the [Serializable] attribute. It is not used by XML Serialization, and it is giving the wrong message to the Data Contract Serializer.
If you are using just XmlSerialization then you can use attributes from System.Xml.Serialization namespace to control Xml-Serialization for example XmlAttributeAttribute.
If you wand to use DataContractSerializer in your Wcf service, you need to mark your class with DataContract attribute and mark all properties with DataMember attribute.
IMHO DataContractSerializer is much more advanced, than old XmlSerialization

How to serialize a class with a complex property using XML serialization in .NET?

I want to serialize a class. In this class there's a property of type Class1 that in turn has its own properties.
public abstract class ComponentBase
{
[ToSerialize] //An attribute defined my me, indicating whether or not to serialize this property.
public ComponentArgs Parameters { get; set; }
}
public class ComponentArgs
{
public string WorkingPath { get; set; }
public IList<Language> Languages { get; set; }
public string ComponentOutputPath { get; set; }
}
The information serialized must be put into a Dictionary<string,string>, such as
ComponentSettings[str_Name] = str_Value;
The method used in reading this value is Reflection
// pinfo: Property Info got via Type.GetProperties();
componentSettings.Add(pinfo.Name, pinfo.GetValue((object)this, null).ToString());
The information after serialization is:
<Parameters>MS.STBIntl.Pippin.Framework.ComponentArgs</Parameters>
instead of the value of ComponentArgs.WorkingPath.
The solution I thought of is to append to the following line an if judgement:
componentSettings.Add(pinfo.Name, pinfo.GetValue((object)this, null).ToString());
if(pinfo is ComponentArgs)
componentSettings.Add(pinfo.Name, pinfo.GetValue(
(ComponentArgs)this, null).WorkingPath+"\n"+
LanguageList+"\n"+ //Language list is a concatinated string of all elements in the list.
(ComponentArgs)this, null).ComponentOutputPath+"\n"+
);
When deserializing, add a judgement of whether the value contains more than 2 "\n", if so, extract each value from the string.
But this way seems clumsy and much more like an workaround. I wonder if there's any more professional way of doing it? My reviewer is very particular and he won't accept such a solution. If you know a way, could you please share it with me? Thanks a lot.
There are lots of ways to use inbuilt serialization.
The simplest and oldest is the [Serializable] attribute that tells .NET to serialize the members.
You can also use the WCF [DataContract] attribute to serialize stuff.
There is also the IXMLSerializable interface which allows you to implement custom XML readers and writers for you classes.
The bottom line is, there is no need to roll your own - it has been done.

Which serializer is most forgiving for changes to the serialized types in .NET?

I noticed the XmlSerializer is more forgiving to adding new members, removing existing ones, etc to the serialized types.
When I did this with the BinaryFormatter, and tried to deserialize the old data, it threw an exception.
What other alternatives are there for forgiving options, i.e. one that doesn't throw an exception just uses default values, skips them, etc?
Are protocol buffers forgiving in this regard?
You mention binary, and indeed BinaryFormatter is very brittle here. The problem is that BinaryFormatter is type and field based. Instead, you want a contract-based serializer, such as XmlSerialzier, DataContractSerializer (3.0), etc.
Or for binary, protobuf-net is a C# implementation of Google's "protocol buffers" wire format, but re-implemented along .NET lines; (note: I'm the author...).
It is (like the others) data-contract based, but instead of <CustomerName>asdasd</CustomerName> etc, it uses numeric tags to identify things instead; so:
[ProtoContract]
public class Customer {
[ProtoMember(1)]
public string Name {get;set;}
// ...
}
As you add more members you give them new unique numbers; this keeps it extensible without relying on any names etc. Plus it is very fast ;-p As with XmlSerializer, it will ignore things it doesn't expect (or it can store them for safe round-trip of unexpected data), and supports the same default things. You can even use your existing xml attributes:
[XmlType]
public class Customer {
[XmlElement(Order=1)]
public string Name {get;set;}
// ...
}
I could talk about this subject all day, so I'd better shut up before [too late].
You could inherit your class from ISerializable and define a custom GetObjectData. I haven't tested this, but such a class might be deserializable from a binary format, even if changes have since been made to the class.
EDIT
I just confirmed that this works. You can use code like the example below to explicitly define how an object is serialized and deserialized. It would then be up to you to make these methods work with older versions of your class. I tested this by serializing an instance of Cereal to a binary file, then making changes to the class and reading the file back in for deserialization.
[Serializable]
private class Cereal : ISerializable
{
public int Id { get; set; }
public string Name { get; set; }
public Cereal()
{
}
protected Cereal( SerializationInfo info, StreamingContext context)
{
Id = info.GetInt32 ( "Id" );
Name = info.GetString ( "Name" );
}
public void GetObjectData( SerializationInfo info, StreamingContext context )
{
info.AddValue ( "Id", Id );
info.AddValue ( "Name", Name );
}
}
I strongly recommend doing your own serialization so that you have well-defined file formats independent of the language schemes.
I actually find that the binary formatter is the most durable in the long run.
It provides excellent forward compatibility. That is to say, if you upgrade the file to a new version, it will not work with the old deserializer.
I generally create some simple data classes that I want to use for serialization. When i need to change the class, I implement the OnDeserialized / OnDeserializing methods. This allows the data to be upgraded.
The binary formatter does not require that you have a public setter for your properties, which to me is a big problem sometimes.
[Serializable]
public class data
{
private int m_MyInteger;
// New field
private double m_MyDouble;
[OnDeserializing]
internal void OnDeserializing(StreamingContext context)
{
// some good default value
m_MyDouble = 5;
}
public int MyInteger
{
get{ return m_MyInteger; }
set { m_MyInteger = value; }
}
}
I think the following post could help you. I also agree with others who said to write your own serializer. It is way better than generated code from xsd.exe .
See the post below:
Serialization and Deserialization into an XML file, C#
You can also look at the OptionalFieldAttribute for use with SerializableAttribute/NonSerializedAttribute and the BinaryFormatter and SoapFormatter
... version 1
[Serializable]
public class MyClass
{
public string field1;
[NonSerialized]
public string field2;
}
... version 2
[Serializable]
public class MyClass
{
public string field1;
[NonSerialized]
public string field2;
[OptionalField]
public string field3;
}

Categories

Resources