netcoredev
netcoredev

Reputation: 75

Determine type of Object in Controller Class

I have a controller mapped to API endpoint which takes a list of objects (say Dog) and then I deserialize it into IEnumerable.How do I know if this object is of type Dog or Cat or whatever ? My controller looks like this

string objectType  = "Dog"  //can be anything like Dog,Cat etc

var list = System.Text.Json.JsonSerializer
    .Deserialize<IEnumerable<objectType>>(content.ToString());

var output = services.InsertObject<objectType>(list);

Obviously I cannot write IEnumerable<objectType> since it throws error. Since I want to pass on this dynamic Object type to other layers as well, I want it to be generic. My methods look like this. InsertObject<T>(IEnumerable<T>items);

Upvotes: 0

Views: 717

Answers (1)

CodeCaster
CodeCaster

Reputation: 151672

By default, you can't have one API endpoint that accepts different object types, because the serializer can't guess which object type to deserialize into.

You need some discriminator to tell the serializer what kind of object to deserialize from the body.

Given this body:

{
    "name": "Foo",
    "size": "Large"
}

Which of these classes does that match?

public class TShirt
{
    public string Name { get; set; }
    public string Size { get; set; }
}

public class Dog
{
    public string Name { get; set; }
    public string Size { get; set; }
}

The point is: it matches both. So if this is an API, you discern by route (/api/tshirts, /api/dogs), and somewhere in your code or configuration you map a route to a class.

You could include this discriminator in your body:

{
    "$type": "Dog",
    "name": "Woof",
    "size": "smol"
}

And then you'd use a hook somewhere to read the $type field and return the appropriate class to deserialize into.

How to do either is another question altogether, and depends on which side of the service you're on (are you writing API controllers or a client for an existing API?) and what frameworks you're using and whatnot.


As for your actual question, you could do something like this:

public void Insert<T>(string json)
{
    var list = System.Text.Json.JsonSerializer
    .Deserialize<IEnumerable<T>>(json);

    var output = services.InsertObject<T>(list);
}

And then call that method through reflection, using a Type obtained from its name.

The amount of horrific code this requires to work should deter you from doing so. If not, see those two questions to write it.

Upvotes: 2

Related Questions