Oliver Zheng
Oliver Zheng

Reputation: 8199

DataContractJsonSerializer throws InvalidCastException for members of varying types

There is a piece of string I'd like to deserialize with DataContractJsonSerializer. There is a member in the JSON string that may be an object sometimes or a string other times. Like so:

{ a: 1, b: 2, c: "c" }

or

{ a: 1, b: 2, c: {c1: 3, c2: 4} }

I know the structure of the object in the second case (let's call that class Inner), but how can DataContractJsonSerializer convert an object of two possible types?

I tried making an explicit and implicit cast operator to convert from string to Inner, but it isn't getting hit. An InvalidCastException keeps on getting thrown.

Upvotes: 1

Views: 504

Answers (1)

bsiegel
bsiegel

Reputation: 237

I had a similar situation, where an API was returning either an array of objects, or just the single object not in an array if there was only one result. I was completely unable to get the DataContractJsonSerializer to do this. I ended up having to switch to the JSON.NET library and fiddle with JsonConverters a bit to get it working.

In your DataContract, declare 'c' as type Inner.

[DataMember(Name = "c")]
public Inner C { get; set; }

Then write a JsonConverter to examine the token type and do the right thing when the deserializer attempts to deserialize an Inner.

internal class StringOrInnerConverter : JsonConverter {
    public override bool CanConvert(Type objectType) {
        return objectType == typeof(Inner);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
        var ser = new JsonSerializer();

        if (reader.TokenType == JsonToken.StartObject) {
            var inn = ser.Deserialize<Inner>(reader);
            return inn;
        } else if (reader.TokenType == JsonToken.String) {
            var str = ser.Deserialize<string>(reader);
            return (Inner)str; // Or however you want to convert string to Inner
        } else {
            return default(Inner);
        }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) {
        throw new System.NotImplementedException();
    }
}

Upvotes: 1

Related Questions