JsonSubTypes icon indicating copy to clipboard operation
JsonSubTypes copied to clipboard

Inherited Class's DataAnnotations are used in ASP.NET

Open PercyODI opened this issue 4 years ago • 4 comments

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.

PercyODI avatar Jul 24 '20 17:07 PercyODI

Does Newtonsoft.Json handle those ?

manuc66 avatar Aug 29 '20 21:08 manuc66

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

manuc66 avatar Feb 26 '21 23:02 manuc66

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

mihailovdumitru avatar Aug 09 '21 12:08 mihailovdumitru

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);
}

bjarketrux avatar Feb 16 '22 12:02 bjarketrux

Thanks @bjarketrux . Your workaround helped me a lot!

Tyrcheg avatar Oct 07 '22 14:10 Tyrcheg

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.

Tyrcheg avatar Oct 09 '22 11:10 Tyrcheg