I’m sorry for the bad title but I really don’t know how to put this any other way. The detailed problem is as follows:
I have a .NET API with Controllers. I have a controller that has a reference to a service of generic type Entity and that returns an IEnumerable
of generic Dto<>
‘s like so:
public class SomeController {
private readonly Service<SomeEntity> _someService;
//constructor
[HttpGet]
public async Task<IEnumerable<Dto<SomeEntity>>> AsyncGetSomeData() {
return await _someService.AsyncGet();
}
}
The Service interface looks like this; it’s purpose is to call a repository for entities and convert the entities to dto’s in a way that a different Dto
could be used for a given Entity
:
public interface Service<T> where T : Entity
{
Task<IEnumerable<Dto<T>>?> AsyncGet();
}
The Entity interface looks like this (for now):
public interface Entity {}
The Dto interface looks like this:
public interface Dto<T> where T : Entity.Entity {}
Implementations of the Entity interface can look like this:
public record SomeEntity (Guid id) : Entity
Implementation of the Dto can look like this:
public record SomeDto(string Id) : Dto<SomeEntity>;
When I return the objects in the way the controller is set up now (as described), empty json objects are returned. This is because the json serializer is not able to figure out that Dto<SomeEntity>
can be serialized as SomeDto
. This is proven by the fact that changing the signature to return IEnumerable<SomeDto>
and casting the items in IEnumerable<Dto<SomeEntity>>
to SomeDto
does in fact serialize the objects correctly.
My question is: is it possible to change a setting or map Dto<SomeEntity>
to SomeDto
or something else to avoid having to change signatures and casting?
I have tried finding examples of something like this (Google and StackOverflow), but as you can see the problem is quite complicated to encapsulate in one sentence (I am accepting title suggestions to improve this question). I hope someone can either point me to a duplicate question or give me an answer.
EDIT:
I am trying to use the JsonDerivedTypeAttribute
. I have two entity types and corresponding dto’s:
public sealed record CourseDto() : Dto<CourseEntity>
public sealed record CourseDefinitionDto() : Dto<CourseDefinitionEntity>
Then, I have defined the JsonDerivedTypeAttribute
on the Dto
interface:
[JsonDerivedType(derivedType: typeof(CourseDto), "a")]
[JsonDerivedType(derivedType: typeof(CourseDefinitionDto), "b")]
public interface Dto<T> where T : Entity.Entity;
No matter what I use in the typeDiscriminator parameter, I get the following error:
"System.InvalidOperationException: Specified type ‘Application.Data.Dto.CourseDto’ is not a supported derived type for the polymorphic type ‘Application.Data.Dto.Dto`1[Application.Data.Entity.CourseDefinitionEntity]’. Derived types must be assignable to the base type, must not be generic and cannot be abstact classes or interfaces unless ‘JsonUnknownDerivedTypeHandling.FallBackToNearestAncestor’ is specified."
2
Answers
If you are using System.Text.Json you should have a look at JsonDerivedTypeAttribute and JsonConverterAttribute
Here is a quick sample of what you could do with
JsonDerivedTypeAttribute
A sample to use
Output
EDIT
Here is a hint to get your controller able to return
Dto
interface, not genericDto<T>
interface.You can do this because
IEnumerable<T>
interface is covariant.Your action signature becomes
I’ve switched
Async
word in method’s name, to be more compliant with C# naming convention.My advice is you give it both classes: