Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 419
rony l Avatar asked Apr 13 '11 08:04

rony l


2 Answers

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
}
like image 150
Cheeso Avatar answered Oct 11 '22 04:10

Cheeso


Adding the namespace parameter to the data contract does the trick. [DataContract(Namespace = "")]

like image 30
rony l Avatar answered Oct 11 '22 03:10

rony l