-
Notifications
You must be signed in to change notification settings - Fork 4.9k
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
[Extensions.Options] ValidateDataAnnotation doesn't work when classes have properties that also have DataAnnotations on their members #36093
Comments
@rynowak When MVC does validation, does it attempt to drill down into composed types like is being requested here? (To me, this seems quite a dangerous approach to take, but wondering if there is a commonly used pattern for it.) |
@ajcvickers Yes, but it will do it once. It get the flat metadata and then attempts to validate it. I think we can just recursively validate options, or maybe make recursive validation optional. |
As part of the migration of components from dotnet/extensions to dotnet/runtime (aspnet/Announcements#411) we will be bulk closing some of the older issues. If you are still interested in having this issue addressed, just comment and the issue will be automatically reactivated (even if you aren't the author). When you do that, I'll page the team to come take a look. If you've moved on or workaround the issue and no longer need this change, just ignore this and the issue will be closed in 7 days. If you know that the issue affects a package that has moved to a different repo, please consider re-opening the issue in that repo. If you're unsure, that's OK, someone from the team can help! |
I'm still interested in having this issue addressed. |
Paging @dotnet/extensions-migration ! This issue has been revived from staleness. Please take a look and route to the appropriate repository. |
Somewhat related to #36391. |
I am also having this issue. In my case it's a Dictionary of items public class MinecraftOptions {
public const string SectionName = "Minecraft";
[Required]
public Dictionary<string, MinecraftServer> Servers { get; set; } = null!;
}
public class MinecraftServer {
[Required, MinLength(1)]
public string Host { get; set; } = null!;
[Required, Range(1, ushort.MaxValue)]
public ushort RconPort { get; set; }
[Required, MinLength(1)]
public string RconPassword { get; set; } = null!;
[Required, Range(1, ushort.MaxValue)]
public ushort QueryPort { get; set; }
} |
Found a workaround for nested objects based on similar StackOveflow question and corresponding Nuget package. It works for nested objects, arrays and dictionaries but requires some preparation:
Usage should be simple - just replace calls of |
I know that it's possible to fix, but this should be part of the .NET runtime. Not an extension method I need to copy to every application I ever work on. |
Options is part of every applications. Some may have lots of. Nesting options is obvious in this case as it helps sorting them. It is even the purpose of the Option pattern. And adding lots of options in the DI to avoid nesting them is not a good idea because you may have a service using many of them and this will result in a method declaration with lots of parameters for each options you need instead having only one option "registry" you can navigate into. |
It would be good to address this in 7.0. |
I could be mistaken, but I think the Example... public class MyModel
{
[Required]
public string? Id { get; set; }
public MySubmodel? PrimarySubmodel { get; set; }
public IEnumerable<MySubmodel>? ExtraSubmodels { get; set; }
}
public class MySubmodel
{
[Required]
public string? Name { get; set; }
}
MyModel invalidModel = new()
{
PrimarySubmodel = new(),
ExtraSubmodels = new[] { new MySubmodel(), new MySubmodel() }
};
List<ValidationResult> results = new();
bool isValid = Validator.TryValidateObject(invalidModel, new ValidationContext(invalidModel), results);
// isValid is false (expected) but results only contains a single error, that Id was missing. Maybe a better solution is to add something in public class MyModel
{
[Required]
public string? Id { get; set; }
[ValidateComplexObject] // System.ComponentModel.DataAnnotations.ValidateComplexObjectAttribute
public MySubmodel? PrimarySubmodel { get; set; }
[ValidateEnumerable] // System.ComponentModel.DataAnnotations.ValidateEnumerableAttribute
public IEnumerable<MySubmodel>? ExtraSubmodels { get; set; }
} |
@maryamariyan I'm happy to look at this one |
Tagging subscribers to this area: @ajcvickers, @bricelam, @roji Issue DetailsDescribe the bugWhen using ValidateDataAnnotations to validate a configuration hierarchy, you can only validate top level members of the class. Any properties that are types which also include validation are NOT validated. Perhaps this was viewed as a design decision, but I think it'd be a lot more consistent if automatic data annotation validation worked in the same fashion as mvc model validation. To Reproduce
public class AnnotatedOptions
{
[Required]
public string Required { get; set; }
[StringLength(5, ErrorMessage = "Too long.")]
public string StringLength { get; set; }
[Range(-5, 5, ErrorMessage = "Out of range.")]
public int IntRange { get; set; }
public AnnotatedOptionsSubsection AnnotatedOptionSubsection { get; set; }
}
public class AnnotatedOptionsSubsection
{
[Range(-5, 5, ErrorMessage = "Really out of range.")]
public int IntRange2 { get; set; }
}
var services= new ServiceCollection();
services
.AddOptions<AnnotatedOptions>()
.Configure(o =>
{
o.StringLength = "111111";
o.IntRange = 10;
o.AnnotatedOptionSubsection = new AnnotatedOptionsSubsection
{
IntRange2 = 10000
};
})
.ValidateDataAnnotations();
[Route("api/[controller]")]
[ApiController]
public class ConfigController : ControllerBase
{
private readonly AnnotatedOptions _configuration;
public ConfigController(IOptionsMonitor<AnnotatedOptions> configuration)
{
try
{
_configuration = configuration.CurrentValue;
}
catch (OptionsValidationException ex)
{
throw new Exception(string.Join(@"\r\n", ex.Failures), ex);
}
}
// GET api/config/
[HttpGet("{configKey}")]
public ActionResult<AnnotatedOptions> Get()
{
return _configuration;
}
}
|
To support this scenario a fix needs to be made lower down in |
The linked PR addresses this issue but has been dormant for a while. It also seems that fixing this might be a 'breaking change'... |
Just hit this!! |
@jchannon - it'd be nice to mark a start on whatever this one turns out to be |
Hey, any news with solution for that issue? |
I'm still keen to work on this. I don't know if a decision has yet been made on which form this validation should take, and where it should live. |
I agree, it would be even more confusing in .NET 8 if |
It seems like this will be fixed in .NET 8 with the new attribute |
Describe the bug
When using ValidateDataAnnotations to validate a configuration hierarchy, you can only validate top level members of the class. Any properties that are types which also include validation are NOT validated.
Perhaps this was viewed as a design decision, but I think it'd be a lot more consistent if automatic data annotation validation worked in the same fashion as mvc model validation.
To Reproduce
The text was updated successfully, but these errors were encountered: