4

We're in a process of switching from Json.NET to ServiceStack.Text and I came across an issue with serialization of polymorphic collections.

In JSON.NET I used to create a custom JsonCreationConverter and overriding the Create() method to select the type I want to create - as outlined here:

http://dotnetbyexample.blogspot.co.uk/2012/02/json-deserialization-with-jsonnet-class.html

The collection in question is List<ItemBase> which can contain FlightItem or CarHireItem objects.

This is my version of the Create() method for JSON.NET:

protected override ItemBase Create(Type objectType, JObject jsonObject)
        {
            var itemType = jsonObject["Type"].ToString();
            switch (itemType)
            {
                case "flight":
                    return new FlightItem();
                case "carhire":
                    return new CarHireItem();
                default: 
                    return null;
            }
        }

Is that possible with ServiceStack?

Serialization and deserialization in ServiceStack for polymorphic collections works, however, it appends the object type to the JSON output, e.g.

"__type" : "TestProject.Model.FlightItem, TestProject"

This means that I need to supply the type when posting JSON and I'm not too keen on having the .NET type visible for anyone within the API calls.

Any suggestions? If it's possible to do this in a different way, can you point me to some examples?

4

1 回答 1

6

Firstly, Interfaces or abstract types in DTOs are a bad idea.

You're now in the strange position where you're trying to support polymorphic types in DTOs, but don't want to provide JSON Serializer-specific info? The reason why you need bespoke code to support polymorphic DTO's is because it's impossible to tell what concrete type should be used based on the wire format, hence why ServiceStack emits the __type property for this purpose.

To avoid these hacks, and have it work equally well in all JSON Serializers, you're better off "flattening" your polymorphic types into a single "flat" DTO and send that across the wire instead. Once you're back in C# you can use code to project it into the ideal types.

ServiceStack does provide some JsConfig<ItemBase>.RawDeserializeFn that will let you do something similar, see the CustomSerializerTests for an example. There's also the JsConfig<ItemBase>.OnDeserializedFn hook that can potentially help, but it's dependent on whether ItemBase contains a complete property list of both concrete types.

于 2013-01-11T18:19:06.823 回答