I am attempting to generate a JSON file that will be used within the Dojo javascript framework and would like to return a position
attribute to be used in a dojo.place()
call. The position
parameter can be either a number or a string.
Using the StructLayout
would not seem to work as-is since the serializer would try to emit both the String and Integer types. I'm looking at creating a custom ContractResolver
that overrides the CreatePrimitiveContract
to return a custom JsonConverter
class. However, looking a the API, it appears that the JsonConverter
is created based on type, and not a specific object value.
How can I handle this case in C# using the Json.NET serializer?
Presumably the solution would involve two properties with custom setters to null out the other property when one is set in conjunction with some sort of custom Json.Net class to inspect the values of the properties and only serialize the non-null one.
** Hypothetical Example **
// C# struct (or class)
[StructLayout(LayoutKind.Explicit)]
struct DojoPosition {
[JsonProperty(PropertyName="position")]
[FieldOffset(0)]
public String StrPos;
[JsonProperty(PropertyName="position")]
[FieldOffset(0)]
public Int32 IntPos;
}
// Serialization output
DojoPosition pos;
pos.StrPos = "only";
var output = JsonConvert.SerializeObject(pos);
// Output is: { "position": "only" }
pos.IntPos = 3;
var output = JsonConvert.SerializeObject(pos);
// Output is: { "position": 3 }
I just had a similiar problem. For simple manipulation of a contract look there: Overriding the serialization behaviour in Json.Net
For resolving a JsonPrimitiveContract override the CreateContract
method.
Here is an example based on our solution:
public class JsonDotNetContractResolver : DefaultContractResolver
{
protected override JsonContract CreateContract(Type objectType)
{
if (typeof(DojoPosition).IsAssignableFrom(objectType))
{
return new JsonPrimitiveContract(objectType.GetGenericArguments()[1])
{
CreatedType = typeof(object), // Not sure this will work for you, or is necessary...
IsReference = false,
Converter = DojoPositionConverter,
};
}
return base.CreateContract(objectType);
}
private class DojoPositionConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var dp = (DojoPosition) value;
if(string.IsNullOrEmpty(dp.StrPos))
serializer.Serialize(writer,dp.IntPos);
else
serializer.Serialize(writer,dp.StrPos);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
//...
}
public override bool CanConvert(Type objectType)
{
//....
}
}
}
How to determine the type to deserialize from the reader is your homework ;)