Json Deserialization with same property name with different case - c#

I want to understand how Json.NET deserializes a JSON object to corresponding c# object when we have multiple property names with different cases(I know this is not a good practice, but just curious to know how JSON.NET deals with this).
I have a c# object defined as below:
public class TestModel
{
public string Name { get; set; }
public bool IsEmployee { get; set; }
}
And json object as
{ "Name": "TestName","Isemployee":true, "isemployee":false};
Then, if I use the JSON.NET de-serialize method to convert above json string to TestModel object, which one of those two properties will be assigned to IsEmployee variable? And why?
Thanks.

In deserialization, Json.NET attempts case insensitive matching of an attribute if exact matching fails, as discussed here. This is in contrast to the built-in .NET JSON serializers, see here.
If multiple matches are detected, the last match takes precedence.

Related

Why is there a setter property in C# when deserializing JSON?

When deserializing from JSON to C# objects, why is there a setter property when you technically you are only "getting" the property from a deserialized JSON object? Wouldn't it be appropriate to just have:
public class Json
{
public string MyKey { get; }
}
Rather than:
public class Json
{
public string MyKey { get; set; }
}
I'm not 100% clear as to why I need the "set" property there for my use-case?
Thanks for the help.
When you are deserializing, you are taking the values from the json string and setting them in the c# object so you need the setters to populate the object.
If you were serializing the c# object to a json string, then you would only need the getter because you are getting the values from the c# object.
The JSon Deserializer has to create an instance of your objects and restore their state (the values of their properties) from the serialized Json Stream.
In order to do so, It needs to be able to inject those value in the instances, either by setting their properties (for which it needs a public setter) or by passing them as a parameter to an appropriate constructor (one which has a parameter of the same name and type as the value that needs to be set).

JSon.NET deserializing object doesn't work

So I have a Client-Server application that is using this class for communication, it contains an object so I can send any kind of data between server and client:
public class comObj
{
public eDisconnectedReason dcReason;
public object payload;
}
Before sending it through the Socket I will serialize it using JSon.Net, e.g.:
string jsonString = JsonConvert.SerializeObject((new Common.comObj() { dcReason = Server.disconnectedReason, payload = Data }), Formatting.None);
now the server receives exactly the string that was sent by the client:
sent string: "{\"dcReason\":4,\"payload\":{\"msg\":\"hi\"}}"
received string: "{\"dcReason\":4,\"payload\":{\"msg\":\"hi\"}}"
however when I try to deserialize the received string into the original comObj:
Common.comObj rcvdObj = JsonConvert.DeserializeObject<Common.comObj>(rcvdString);
rcvdObj.payload is of type Newtonsoft.Json.Linq.JObject instead of object.
Let us start by considering your JSON input:
{
"dcReason": 4,
"payload": {
"msg": "hi"
}
}
Using Json.NET you have two key ways of deserializing JSON data. You can:
Deserialize it into a specific concrete type
You can deserialize it into the generic JToken type. (In your case, it instantiates a JObject -- a subclass of JToken -- because JSON.Net recognized that the JSON input specified an object, as opposed to a primitive type or an array)
In your case, you actually ended up with a hybrid of both approaches. Since you specified a specific type for the root object, it returned an instance of comObj. Since you merely specified object as the type of the property payload, Json.NET did its best and simply reverted to option 2) and gave you an instance of JObject, which contains the data such as msg.
You have two options to solve your problem. You can:
Interrogate the payload property as a JObject, like you would have had to do for the entire JSON body if you had not used option 1).
Define a concrete type to represent the payload property. I strongly recommend this approach, as it is considerably more typesafe and also easier to work with.
To achieve the former, you can use faclities such as o["msg"] -- essentially like a dictionary.
To achieve the latter -- which I would recommmend -- simply define a type for payload. In other words, change you code to:
public class comObj
{
public eDisconnectedReason dcReason;
public Payload payload;
}
public class Payload
{
public string msg { get; set; }
}
Now when you deserialize your JSON, you'll be able to use the syntax:
Console.WriteLine(rcvdObj.payload.msg);
And -- importantly -- if you later decide to rename msg in your JSON payload to, say, message you will be able to properly refactor the property msg of payload to message and expect all usages to be fixed. This is obviously less robust when using strings.

Is it possible to set custom (de)serializers for open generic types in ServiceStack.Text?

I have a type like this:
class Foo<T>
{
public string Text { get; set; }
public T Nested { get; set; }
public static string ToJson(Foo<T> foo) { [...] }
}
ToJson serializes a Foo<Bar> instance to JSON in a way that is impossible to achieve by tweaking JsConfig. Also, ToJson relies on ServiceStack.Text to serialize Nested, which can be an instance of Foo<Baz>.
Unfortunately, the way JsConfig is implemented implies that there will be a JsConfig<T> set of static variables for Foo<Bar> and other for Foo<Baz>. Also, AFAIK, ServiceStack.Text offers no way to configure JSON serialization for open generic types (i.e.: something like JsConfig.Add(typeof(Foo<>), config)). I tried to solve this issue by creating this static constructor for Foo<T>:
static Foo() {
JsConfig<Foo<T>>.RawSerializeFn = ToJson;
}
This doesn't work all the time. It depends on the order the static constructors are invoked by the runtime. Apparently, ServiceStack.Text caches serializers functions and sometimes is doing it before the static constructor is called depending on the order operations are invoked in the API, so:
var outer = new Foo<Baz> { Text = "text" };
outer.ToJson(); // OK, because Nested is null
var inner = new Foo<Bar>();
inner.ToJson(); // OK, because JsConfig<Foo<Bar>>.RawSerializeFn is Foo<T>.ToJson
outer.Nested = inner;
outer.ToJson(); // NOT OK, because SS.Text uses the default serializer for Foo<T>, not Foo<T>.ToJson
I can't set all the serializers in JsConfig<Foo<T>> beforehand because T can be virtually any type, even other generic types.
Is it possible to define custom serialization routines for open generic types (that can be nested) in ServiceStack.Text?
I solved for this in my own way with a wrapper and a custom deserializer. I created a base type for all of my abstract types. That base type tells the system which type it is:
public class SetSettingItemBase
{
public string Key { get; set; }
public string ValueType { get; set; }
}
So the base is essentially the metadata -- the setting key + the value type. The object DTO, then, simply extends it by adding the actual value:
public class SetSettingItem : SetSettingItemBase
{
public object Value { get; set; }
}
Note that it's just an object. This is the DTO, not my actual object. I can cast it later, or convert it to a real/generic type after serialization.
My custom serialization then is:
JsConfig<SetSettingItem>.RawDeserializeFn = str =>
{
var baseSettings = str.FromJson<SetSettingItemBase>();
var ret = baseSettings.MapTo<SetSettingItem>();
if(true) // actual condition removed here... unimportant to the example
{
var dataType = Constants.KnownSettingsTypes[baseSettings.ValueType];
var method = typeof(JsonExtensions).GetMethod("JsonTo").MakeGenericMethod(dataType);
var key = "Value";
var parsed = JsonObject.Parse(str);
if(parsed.Object(key) == null)
key = "value";
ret.Value = method.Invoke(null, new object[] { parsed, key });
}
return ret;
};
This method first deserializes to the simple base. So the Value passed in from the DTO is ignored when deserializing baseSettings. I then call MapTo to prepare the actual SetSettingItem DTO. MapTo is just a wrapper around AutoMapper. You could just as easily use SS's built in mapper here.
For security, I have a set list of types that I allow as settings. Example:
KnownSettingsTypes.Add("string", typeof(string));
KnownSettingsTypes.Add("int", typeof(int));
KnownSettingsTypes.Add("nullableint", typeof(int?));
KnownSettingsTypes.Add("nullablepercentage", typeof(double?));
KnownSettingsTypes.Add("feegrid", typeof(FeeGrid));
After that, I use reflection to get the JsonTo method, passing in the generic type parameter dynamically from the KnownSettingsTypes dictionary.
And then finishing it all up, I parse the object using the generic JsonObject.Parse method and then looking for the Value or value (depending on case sensitivity) and explicitly convert that JsonObject using the dynamic method I created earlier.
The end result is I can pass in settings of all different types here as a part of my DTOs.
This served my purposes for the time being, but looking at the example I could see it improving in two ways:
After parsing, I could convert my SetSettingItem to a SettingItem<T> so I could use it as a strongly-typed object in my code. Remember, this example is just for the DTOs to get it across the wire.
Instead of requiring the person to pass in the type for me to check against, I could check against the setting Key to know which type it is supposed to be and parse accordingly. In my example, even if I check against the master list of settings and their types, I'd still probably require them to pass in the type just as a precaution and throw an exception if they didn't match.

How to serialize class type but not the namespace to a Json string using DataContractJsonSerializer

I'm trying to serialize a class hierarchy to a Json string using DataContractJsonSerializer, in a WCF service.
the default behaviour for serializing a derived class is to add the following key value pair to the object:
"__type":"ClassName:#Namespace"
My problem is that namespaces are long and they bloat the Json string.
I would like to somehow intervene with the serialization and output this instead:
"__type":"ClassName"
and on deserialization intervene again to point to the correct namespace (which i know in runtime).
Is there any way to do such a thing?
This page describes the circumstances under which the __type property is emitted. In short, in WCF, if you use a derived type, and a KnownTypeAttribute, then you're going to get a __type property.
Example:
Assume
[DataContract]
[KnownType(typeof(Subscriber))]
public class Person { ... }
[DataContract]
public class Subscriber : Person { ... }
This code generates a __type property:
var o = new Subscriber("Fleming");
var serializer = new DataContractJsonSerializer(typeof(Person));
serializer.WriteObject(Console.OpenStandardOutput(), o);
But this code does not:
var o = new Subscriber("Fleming");
var serializer = new DataContractJsonSerializer(typeof(Subscriber));
serializer.WriteObject(Console.OpenStandardOutput(), o);
Notice that the second snip uses a DCJS with the same type as the object being serialized.
To avoid the __type, don't use derived types, or to be precise, use a serializer typed to the type you are actually serializing. If the serialization is being performed implicitly by a WCF method, then the method must be typed appropriately. In my example, it means you must use a return type of "Subscriber", and not the parent type, "Person".
The __type is emitted into the JSON stream by the (private) WriteServerTypeAttribute method on the
(internal) System.Runtime.Serialization.Json.XmlJsonWriter class. There is no public, documented, supported way to modify that, as far as I can tell.
To avoid this, you'd maybe need to return a string from the WCF method, perform the serialization yourself, and post-process the emitted JSON.
If you don't mind the __type thing, but just want to remove the qualifying namespace from the value, then put your types in the global namespace. In other words, put them outside of any namespace declaration in code.
Example: When the data types reside in a namespace, and when I used a derived type, the serialized JSON looks like this:
{
"__type":"Subscriber:#My.Custom.Namespace",
"Index":604455,
"Name":"Fleming",
"Id":580540
}
When the data types reside in the global namespace, it looks like this:
{
"__type":"Subscriber:#",
"Index":708759,
"Name":"Fleming",
"Id":675323
}
Adding the namespace parameter to the data contract does the trick.
[DataContract(Namespace = "")]
Cheeso's answer was excellent. I did discover a refinement to cleaning up the __type field though:
Rather than removing your subclass from its namespace you can add a property like the following:
[DataMember(Name = "__type")]
public string SubclassType
{
get
{
return "Subscriber";
}
set { }
}
You still get stuck with the ugly name "__type" but I found that because I was returning a list of subtypes I wanted to specify the type name anyway. You could even return a value of "" to further reduce response size. You could also just declare the property as:
public string __type
but I found that to accentuate the hack so I stuck with an appropriate property name and then renamed it.
-Joey
Note: I typed up this answer below and later realized that DataContractResolver is currently not supported with DataContractJsonSerializer. It may soon be with the next release of the framework, however. This is also useful if you are looking at more than just JSON.
**
You can do this with a DataContractResolver, which lets you map types to xsi:type (__type) information and vice-versa in a custom manner.
To do this, check out this blog post on DataContractResolver, plus this conceptual topic, plus this sample
#Cheeso wrote:
To avoid this, you'd maybe need to return a string from the WCF
method, perform the serialization yourself, and post-process the
emitted JSON.
Here's how I implemented that post-processing. I thought I'd post it here JIC it might help someone else.
First some boilerplate to show how I generate my JSON string:
// Instantiate & populate the object to be serialized to JSON
SomeClass xyz = new SomeClass();
... populate it ...
// Now serialize it
DataContractJsonSerializer ser = new DataContractJsonSerializer(xyz.GetType()); // Note xyz.GetType()
... serialize the object to json, many steps omitted here for brevity ...
string json = sr.ReadToEnd();
(Serialization is based on examples from https://msdn.microsoft.com/en-us/library/bb412179%28v=vs.110%29.aspx )
Note that the [DataContract] on SomeClass does not include the (name="") syntax that I've seen suggested elsewhere. That only removes the namespace from the __type at the cost of needing to adorn ALL your DataContract attrs, which clutters your code. Instead, my post-processor handles the assembly name in the __type field.
And now the string json contains the JSON text, but unfortunately includes all that "__type" junk that you don't want but can't suppress.
So here's my post-processing code that removes it:
// This strips out that unsuppressable __type clutter generated by the KnownType attributes
Attribute[] attrs = Attribute.GetCustomAttributes(xyz.GetType());
foreach (Attribute attr in attrs)
{
if (attr is KnownTypeAttribute)
{
KnownTypeAttribute a = (KnownTypeAttribute)attr;
string find = "\"__type\":\"" + a.Type.ReflectedType.Name + "." + a.Type.Name + ":#" + a.Type.Namespace + "\",";
json = json.Replace(find, "");
}
}
This makes a few assumptions, most notably that the __type field ends with a comma, which assumes that another field follows it, though (a) my objects always have at least 1 field and (b) I've found that the __type field is always 1st in the serialized object's output.
As always, you may have to adjust something to your situation, but I find it works well for mine.
Some times ago i decided this problem.
I use DataContractJsonSerializer
You will have __type in json, if your method for serialization have Base class parameter, but you give it subClass as parameter.
More details:
[DataContract]
[KnownType(typeof(B))]
public abstract class A
{
[DataMember]
public String S { get; set; }
}
[DataContract]
public class B : A
{
[DataMember]
public Int32 Age { get; set; }
}
public static String ToJson<T>(this T value)
{
var serializer = new DataContractJsonSerializer(typeof(T));
using (var stream = new MemoryStream())
{
serializer.WriteObject(stream, value);
return Encoding.UTF8.GetString(stream.ToArray());
}
}
You have two methods for test:
public static void ReadTypeDerived(A type)
{
Console.WriteLine(ToJson(type));
}
and
public static void ReadType<T>(T type)
{
Console.WriteLine(ToJson(type));
}
In first test you wiil have
"{\"__type\":\"B:#ConsoleApplication1\",\"S\":\"Vv\",\"Age\":10}"
In second:
"{\"S\":\"Vv\",\"Age\":10}"

Serialize custom type property to string using JavascriptSerializer

I am using the .NET JavascriptSerializer class for a while now to serialize my object to a JSON representation and use it on the client side. Everything works great as long as I stick with the default types like int, string, etc. However, now I want to serialze a custom type property on my object. Let look at an example of my class:
public class ClientData
{
public Guid Id { get; set; }
public string Description { get; set; }
public MyCustomObject ObjectX { get; set; }
}
Wat I want is a clientside object that looks something like this:
{ Id: 0000-0000-000-0000, Description: "some description", ObjectX: "125.20" }
To make this work, I tried using a JavaScriptConverter but that doesn't seem to solve the problem because it can only handle dictionaries, what will make the result look like this:
{ Id: 0000-0000-000-0000, Description: "some description", ObjectX: { Value: "125.20"} }
That's not what I want. I did implement the toString on the MyCustomObject class by the way.
Any suggestions?
Thanks allot.
here is the msdn page to javascriptserializer:
http://msdn.microsoft.com/en-us/library/system.web.script.serialization.javascriptserializer.aspx
in the remark section it says:
To serialize an object, use the Serialize method. To deserialize a JSON string, use the Deserialize or DeserializeObject methods. To serialize and deserialize types that are not natively supported by JavaScriptSerializer, implement custom converters by using the JavaScriptConverter class. Then register the converters by using the RegisterConverters method.
so you should look at this class:
http://msdn.microsoft.com/en-us/library/system.web.script.serialization.javascriptconverter.aspx
Using a JsonConverter from the Json.NET library seems to do the trick for me.
You can convert a custom object into a string. You use a JavaScriptConverter that converts your object into a Uri instance that also implements IDictionary to allow it to pass out of the JavaScriptConverter.
This hack is described for DateTime objects here:
http://blog.calyptus.eu/seb/2011/12/custom-datetime-json-serialization/

Categories

Resources