Binding Runtime Types

Hi,

We have an API method that accepts a list of responses - Responses could be of various types = Number, Text, Date, List etc. Each of these link to a specific model e.g. NumberModel, TextModel, DateModel etc. all which inherit BaseResponseModel.

The request dto is defined to accept a list of BaseResponseModel and based on the response type id, we are planning on instantiating a specific type.

Based on the documentation

We have tried

JsConfig.TypeAttr = “ResponseTypeId”;
and
JsConfig.TypeAttr = “$type”; (as per doco)

// This does not work. Still requires a field __type to be passed in the model.

JsConfig.TypeFinder = typeId =>
{
var fieldTypeId = Guid.Parse(typeId);
if (fieldTypeId == ResponseType.Number)
return typeof(NumberModel);
return typeof(TextModel);
};

Also, is there any way to limit the TypeFinder to run only for a specific request type?
I would appreciate any assistance with this.

Thanks,
Leeny

We’ve always strongly discouraged against poor API Designs with unknown polymorphic data types like this which is going to be a source of runtime issues that wont be able to work with most Add ServiceStack Reference languages. Whilst polymorphic types in DTOs are heavily discouraged, at the very minimum BaseResponseModel should be an abstract type to force embedding __type info.

Which doco is telling you to change TypeAttr to use $type?

I would recommend following the same approach Amazon does in its DynamoDB APIs that need to handle multiple different Types in its AttributeValue Type where it contains a DTO with explicit properties for different value types.

Basically the 2 approaches I would take to model this in a Typed API is to either flatten all types to use a single type with a Type indicating what Type it is, e.g:

public ResponseModel
{
    public string Type { get; set; }
    //.... All properties from all sub Types
}

// Which you can use as normal:
List<ResponseModel> Results { get; set; }

Then if you need to in your App you can convert the flatten DTO ResponseModel into your preferred .NET polymorphic types.

Or have a strong typed collection for each model, e.g:

public List<TextModel> Texts { get; set; }
public List<NumberModel> Numbers { get; set; }

The other lesser recommended approach is to change to use unknown object like List<object> where it gets deserialized into an untyped object dictionary that you dehydrate back into your preferred Type, in which case the FromObjectDictionary extension method can help convert an object dictionary into a concrete type.

Thanks Mythz for your recommendations.

This is the doco that I was trying to follow:
https://docs.servicestack.net/json-format#late-bound-object-and-interface-runtime-types

Note: that’s not a recommendation, that’s just showing how you can change the serializer-specific __type property, you’d only change the default if you had a good reason to as you would need to change both client/server where it’s used.

Thank you. Will follow one of the other two approaches.

1 Like