Up to now I've used Microsoft's DataContractJsonSerializer to serialize and deserialize my business objects into data transfer objects (DTO) formatted as JSON. The DTOs are marked with the DataContract attribute. A small example:
[DataContract(Name = "Geometry", Namespace = "myContract.com/dto")]
[KnownType(typeof(Point))]
[KnownType(typeof(Line))]
public class Geometry
{
}
[DataContract(Name = "Point", Namespace = "myContract.com/dto")]
public class Point : Geometry
{
[DataMember(Name = "x")]
public double X { get; set; }
[DataMember(Name = "y")]
public double Y { get; set; }
}
[DataContract(Name = "Line", Namespace = "myContract.com/dto")]
public class Line: Geometry
{
[DataMember(Name = "start")]
public Point Start { get; set; }
[DataMember(Name = "end")]
public Point End { get; set; }
}
This gets serialized as:
"geometry":{"__type":"Point:myContract.com/dto","x":23133.75569999963,"y":21582.385849999264}
Because of performance issues I switched to Newtonsoft Json.NET. When using this, the JSON strings looks like this:
"geometry":{"$type":"A.B.C.Point, A.B.C","x":23133.75569999963,"y":21582.385849999264}
Is there are possibility to serialize the object with Json.NET into a Microsoft-conform JSON string using "__type" and the contract namespace instead of "$type" and the class-assembly-combination? I'm using .NET 3.5.
Thanks in advance!
Unfortunately it does not seem possible to adjust property name since it is declared in internal JsonTypeReflector.cs class as:
public const string TypePropertyName = "$type";
Note: from another hand, type property value could be customized, SerializationBinder Class is intended for that purpose, this example demonstrates how to specify custom type property value.
I would propose the following solution that allows to write custom type property . First, we need to introduce base entity class (or modify Geometry
class) with type property as demonstrated below
[DataContract(Name = "Entity", Namespace = "myContract.com/dto")]
public abstract class Entity
{
[DataMember(Name = "__type", Order = 0)]
public string EntityTypeName
{
get
{
var typeName = GetType().Name;
if (Attribute.IsDefined(GetType(), typeof(DataContractAttribute)))
{
var attribute = GetType().GetCustomAttributes(typeof(DataContractAttribute), true).FirstOrDefault() as DataContractAttribute;
if (attribute != null) typeName = typeName + ":" + attribute.Namespace;
}
return typeName;
}
}
}
Then modify Geometry
class:
[DataContract(Name = "Geometry", Namespace = "myContract.com/dto")]
[KnownType(typeof(Point))]
[KnownType(typeof(Line))]
public class Geometry : Entity
{
}
And the last step, set JsonSerializerSettings.TypeNameHandling
to TypeNameHandling.None
in order the deserializer to skip the rendering of $type
attribute.
Example
var point = new Point { X = 23133.75569999963, Y = 21582.385849999264 };
var jsonPoint = JsonConvert.SerializeObject(point, new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.None, //do not write type property(!)
});
Console.WriteLine(jsonPoint);
Result
{\"__type\":\"Point:myContract.com/dto\",\"x\":23133.75569999963,\"y\":21582.385849999264}
PS
You could also specify the order using DataMember.Order as shown below:
[DataContract(Name = "Point", Namespace = "myContract.com/dto")]
public class Point : Geometry
{
[DataMember(Name = "x",Order = 1)]
public double X { get; set; }
[DataMember(Name = "y", Order = 2)]
public double Y { get; set; }
}
[DataContract(Name = "Line", Namespace = "myContract.com/dto")]
public class Line : Geometry
{
[DataMember(Name = "start", Order = 1)]
public Point Start { get; set; }
[DataMember(Name = "end", Order = 2)]
public Point End { get; set; }
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.