Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

System.Text.JSON polymorphic behaviour not supported #2571

Closed
Stepami opened this issue Dec 8, 2022 · 8 comments · Fixed by #3170
Closed

System.Text.JSON polymorphic behaviour not supported #2571

Stepami opened this issue Dec 8, 2022 · 8 comments · Fixed by #3170
Milestone

Comments

@Stepami
Copy link

Stepami commented Dec 8, 2022

Beginning with .NET 7, System.Text.Json supports polymorphic type hierarchy serialization and deserialization with attribute annotations.

https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/polymorphism

But if we configure swagger to use polymorphism it does not add information about derived type to docs.

As I think, the problem is that [JsonDerivedType] adds implicit discriminator property which can be seen in json string only.

So, it is interesting to know the plans for support of this feature in library.

@Tungsten78
Copy link

Ideally, Swashbuckle would be able to infer what it needs from the new attributes.

Currently, there's a need to duplicate

  [JsonPolymorphic(TypeDiscriminatorPropertyName = "type")]
  [SwaggerDiscriminator("type")] //the need to duplicate may one day be removed, see https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/2571
  [JsonDerivedType(typeof(AnyCriteria), "Any")]
  [SwaggerSubType(typeof(AnyCriteria), DiscriminatorValue = "Any")]
  [JsonDerivedType(typeof(EqualCriteria), "Equal")]
  [SwaggerSubType(typeof(EqualCriteria), DiscriminatorValue = "Equal")]
  [JsonDerivedType(typeof(GreaterThanCriteria), "GreaterThan")]
  [SwaggerSubType(typeof(GreaterThanCriteria), DiscriminatorValue = "GreaterThan")]
  [JsonDerivedType(typeof(LessThanCriteria), "LessThan")]
  [SwaggerSubType(typeof(LessThanCriteria), DiscriminatorValue = "LessThan")]
  [JsonDerivedType(typeof(BetweenCriteria), "Between")]
  [SwaggerSubType(typeof(BetweenCriteria), DiscriminatorValue = "Between")]
  public abstract record Criteria;

  public record AnyCriteria : Criteria;

  public record EqualCriteria : Criteria;

  public record GreaterThanCriteria(bool OrEqual, decimal Value) : Criteria;

  public record LessThanCriteria(bool OrEqual, decimal Value) : Criteria;

  public record BetweenCriteria(bool OrEqual, decimal From, decimal To) : Criteria;

@Stepami
Copy link
Author

Stepami commented Feb 21, 2023

Eventually, i've made the NuGet package that solves my problem.
It works due to the following algorithm:

  1. Scan predefined through appsettings.json file assemblies for classes marked with [JsonDerivedType]. Those types are the roots of hierarchies.
  2. Those roots are being transformed to hierarchies thanks to attribute metadata and cached into the singleton repository.
  3. Custom ISchemaFilter implementation enriches documentation with additional discriminator info using consumed data before.

Obviously, the solution is not perfect as it requires knowledge about assemblies containing polymorphic contracts and obligates a developer to build hierarchy according to certain limitations.

More information provided in repository of package:
https://github.com/Stepami/swagger-discriminator-setup

@benlongo
Copy link

It's relatively straightforward to use SelectSubTypesUsing, SelectDiscriminatorNameUsing and SelectDiscriminatorValueUsing to make this work I think

@Stepami
Copy link
Author

Stepami commented May 13, 2023

@benlongo not really. We cannot specify the type of discriminator and map it to allowed values in some kind of enum with corresponding defaults.

@schnerring
Copy link
Contributor

schnerring commented Jun 16, 2023

@benlongo not really. We cannot specify the type of discriminator and map it to allowed values in some kind of enum with corresponding defaults.

Well, STJ deserialization doesn't actually put the discriminator value into a property, so enum-valued type discriminators would be a thing of the past.

The docs on customizing the type discriminator name also state:

Avoid using a JsonPolymorphicAttribute.TypeDiscriminatorPropertyName that conflicts with a property in your type hierarchy.

Related issue: dotnet/runtime#72170

@Havunen
Copy link

Havunen commented Feb 24, 2024

FYI This should work in DotSwashbuckle

@martincostello martincostello added the help-wanted A change up for grabs for contributions from the community label Apr 14, 2024
@martincostello
Copy link
Collaborator

#2671 (comment)

@martincostello
Copy link
Collaborator

#3170

@martincostello martincostello removed the help-wanted A change up for grabs for contributions from the community label Nov 25, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment