manuc66 / JsonSubTypes

Discriminated Json Subtypes Converter implementation for .NET
https://manuc66.github.io/JsonSubTypes/
MIT License
412 stars 56 forks source link

Inherited Class's DataAnnotations are used in ASP.NET #111

Closed PercyODI closed 1 year ago

PercyODI commented 4 years ago

Is your feature request related to a problem? Please describe. When using ASP.NET for WebAPIs, DataAnnotations are used to automatically build BadRequest problem objects when Model Binding. However, models using JsonSubTypes do not enforce the DataAnnotations

Describe the solution you'd like I'd like DataAnnotations to be considered, and return BadRequest with a correct problem object when they are not met.

Describe alternatives you've considered A clear and concise description of any alternative solutions or features you've considered.

Additional context Microsoft Documentation on DataAnnotations in ASP.NET: https://docs.microsoft.com/en-us/aspnet/core/mvc/models/validation?view=aspnetcore-3.1

*** Source/destination types

public class AccountNewDto
{
      [Required]
      public string Name { get; set; }

      [Required]
      public string Product { get; set; }

      public ExternalCashAccountType1Code CashAccountType { get; set; } = ExternalCashAccountType1Code.TRAN;
      public AccountStatusEnum Status { get; set; } = AccountStatusEnum.enabled;

      [Required]
      public UsageEnum Usage { get; set; }

      [Required]
      public AmountInDto InitialBalance { get; set; }

      [Required]
      public string Msisdn { get; set; }

      public AmountInDto AuthorizedLimit { get; set; }
}

[JsonConverter(typeof(JsonSubtypes), nameof(AmountInDto.Currency))]
[JsonSubTypes.JsonSubtypes.KnownSubType(typeof(GalacticCurrencyStandardInDto), CurrencyEnum.GSC)]
[JsonSubTypes.JsonSubtypes.KnownSubType(typeof(WizardingCurrencyInDto), CurrencyEnum.WC)]
public class AmountInDto
{
      [Required]
      public CurrencyEnum Currency { get; set; }
}

public class GalacticCurrencyStandardInDto : AmountInDto
{
      [Required]
      public long? Amount { get; set; }
}

public class WizardingCurrencyInDto : AmountInDto
{
      [Required]
      public long? Galleons { get; set; }

      [Required]
      public long? Sickles { get; set; }

      [Required]
      public long? Knuts { get; set; }
}

*** Source/destination JSON

{
  "name": "Test Account",
  "product": "Test Checking",
  "cashAccountType": "TRAN",
  "status": "enabled",
  "usage": "PRIV",
  "initialBalance": {
    "amount": 5000,
    "currency": "WC"
  },
  "msisdn": "555-555-5555"
}

This JSON should return:

{
    "errors": {
        "InitialBalance.Knuts": [
            "The Knuts field is required."
        ],
        "InitialBalance.Sickles": [
            "The Sickles field is required."
        ],
        "InitialBalance.Galleons": [
            "The Galleons field is required."
        ]
    },
    "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
    "title": "One or more validation errors occurred.",
    "status": 400,
    "traceId": "|73003b8f-4ac38906d681633e."
}

But instead it sets the properties to null, despite the [Required] annotation.

manuc66 commented 4 years ago

Does Newtonsoft.Json handle those ?

manuc66 commented 3 years ago

@PercyODI did you tried to use : https://www.newtonsoft.com/json/help/html/JsonPropertyRequired.htm ?

mihailovdumitru commented 3 years ago

@manuc66 is skipping all the addnotations from DataAnnotations, I tried also Required, Range... and nothing is working.

bjarketrux commented 2 years ago

I believe the problem is with asp.NET and not JsonSubTypes nor Newtonsoft.

See: https://github.com/dotnet/aspnetcore/issues/13829 (old) and https://github.com/dotnet/aspnetcore/issues/27882#issuecomment-785527786 (open)

I did a workaround where I specifically call TryValidateModel on each object that is an abstract class:

foreach (var item in polymorphicList)
{
    TryValidateModel(item);
}

if (!ModelState.IsValid)
{
    return ValidationProblem(ModelState);
}
Tyrcheg commented 2 years ago

Thanks @bjarketrux . Your workaround helped me a lot!

Tyrcheg commented 2 years ago

Upd to

I believe the problem is with asp.NET and not JsonSubTypes nor Newtonsoft.

See: dotnet/aspnetcore#13829 (old) and dotnet/aspnetcore#27882 (comment) (open)

I did a workaround where I specifically call TryValidateModel on each object that is an abstract class:

foreach (var item in polymorphicList)
{
    TryValidateModel(item);
}

if (!ModelState.IsValid)
{
    return ValidationProblem(ModelState);
}

Also when TryValidateModel for nested types a call needs to be provided with a prefix.