Api that received generic type

From REST perspective you better of with separate SaveBus, SaveCar and SaveTruck endpoints, cause otherwise you lose self-description and resource identification (though, it is discussable) But if you really need this, you can do this, and moreover it is supported by Swagger (OpenAPI), there this feature is called polymorphism (surprise-surprise) – https://swagger.io/docs/specification/data-models/inheritance-and-polymorphism/

How to achieve in .NET:

In your base class you need a discrimantor property by which later on you will decide what real type to use in your custom json converter:

public class Vahicle
{
    public string Discriminator {get;set;}
    ...
}

Then you create your own custom JSON Converter:

public class VahicleConverter : JsonConverter
{
    private string _discriminator { get; set; } = "Discriminator";

    public VahicleConverter ()
    {

    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null) return null;

        var jDerivedObject = JObject.Load(reader);

        var discriminator = jDerivedObject.Value<string>(_discriminator);
        if (string.IsNullOrWhiteSpace(discriminator))
            throw new Exception("Invalid discriminator value");

        var derivedType = objectType;
        switch(discriminator)
        {
            case "Bus":
                derivedType = typeof(Bus);
            case "Truck ":
                derivedType = typeof(Truck);
            default:
                throw new Exception("Unknown type");
        }

        var derivedObject = Activator.CreateInstance(derivedType);

        serializer.Populate(jDerivedObject.CreateReader(), derivedObject);

        return derivedObject;
    }

    public override bool CanConvert(Type objectType) => true;

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

    //Not required
    public override bool CanWrite => false;
}

Then you need to instruct .NET JSON serializer to use your custom serializer, by simple adding [JsonConverter(typeof(VahicleConverter))] attribute to your class:

[JsonConverter(typeof(VahicleConverter))]
public class Vahicle
{
    public string Discriminator {get;set;}
    ...
}

Now you can have you API action like:

[HttpPost]
public Task<Result> AddVahicle([FromBody]Vahicle model)

And request your action with JSON containing your discriminator:

{
   Dicriminator:"Bus",
   BusSpecificProp:"1",
   ...
}

Sorry if above code have some typos, i haven’t run this exact code, but i’ve used similar in the past, and yeah, additional kudos goes to this answer – https://stackoverflow.com/a/51815457/7064030

CLICK HERE to find out more related problems solutions.

Leave a Comment

Your email address will not be published.

Scroll to Top