@@ -1610,15 +1610,15 @@ public partial class FirstModelValidator : IValidateOptions<FirstModel>
16101610
16111611 // Run the generator with C# 7.0 and verify that it fails.
16121612 var ( diagnostics , generatedSources ) = await RoslynTestUtils . RunGenerator (
1613- new Generator ( ) , refAssemblies . ToArray ( ) , new [ ] { source } , includeBaseReferences : true , LanguageVersion . CSharp7 ) . ConfigureAwait ( false ) ;
1613+ new OptionsValidatorGenerator ( ) , refAssemblies . ToArray ( ) , new [ ] { source } , includeBaseReferences : true , LanguageVersion . CSharp7 ) . ConfigureAwait ( false ) ;
16141614
16151615 Assert . NotEmpty ( diagnostics ) ;
16161616 Assert . Equal ( "SYSLIB1216" , diagnostics [ 0 ] . Id ) ;
16171617 Assert . Empty ( generatedSources ) ;
16181618
16191619 // Run the generator with C# 8.0 and verify that it succeeds.
16201620 ( diagnostics , generatedSources ) = await RoslynTestUtils . RunGenerator (
1621- new Generator ( ) , refAssemblies . ToArray ( ) , new [ ] { source } , includeBaseReferences : true , LanguageVersion . CSharp8 ) . ConfigureAwait ( false ) ;
1621+ new OptionsValidatorGenerator ( ) , refAssemblies . ToArray ( ) , new [ ] { source } , includeBaseReferences : true , LanguageVersion . CSharp8 ) . ConfigureAwait ( false ) ;
16221622
16231623 Assert . Empty ( diagnostics ) ;
16241624 Assert . Single ( generatedSources ) ;
@@ -1638,6 +1638,129 @@ public partial class FirstModelValidator : IValidateOptions<FirstModel>
16381638 Assert . Equal ( 0 , diags . Length ) ;
16391639 }
16401640
1641+ [ ConditionalFact ( typeof ( PlatformDetection ) , nameof ( PlatformDetection . IsNotBrowser ) , nameof ( PlatformDetection . IsNetCore ) ) ]
1642+ public async Task DataAnnotationAttributesWithParams ( )
1643+ {
1644+ var ( diagnostics , generatedSources ) = await RunGenerator ( @"""
1645+ public class MyOptions
1646+ {
1647+ [Required]
1648+ public string P1 { get; set; }
1649+
1650+ [Length(10, 20)]
1651+ public string P2 { get; set; }
1652+
1653+ [AllowedValues(10, 20, 30)]
1654+ public int P3 { get; set; }
1655+
1656+ [DeniedValues(""One"", ""Ten"", ""Hundred"")]
1657+ public string P4 { get; set; }
1658+ }
1659+
1660+ [OptionsValidator]
1661+ public partial class MyOptionsValidator : IValidateOptions<MyOptions>
1662+ {
1663+ }
1664+ """ ) ;
1665+
1666+ Assert . Empty ( diagnostics ) ;
1667+ Assert . Single ( generatedSources ) ;
1668+
1669+ var generatedSource = """
1670+
1671+ // <auto-generated/>
1672+ #nullable enable
1673+ #pragma warning disable CS1591 // Compensate for https://github.com/dotnet/roslyn/issues/54103
1674+ namespace Test
1675+ {
1676+ partial class MyOptionsValidator
1677+ {
1678+ /// <summary>
1679+ /// Validates a specific named options instance (or all when <paramref name="name"/> is <see langword="null" />).
1680+ /// </summary>
1681+ /// <param name="name">The name of the options instance being validated.</param>
1682+ /// <param name="options">The options instance.</param>
1683+ /// <returns>Validation result.</returns>
1684+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")]
1685+ public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::Test.MyOptions options)
1686+ {
1687+ global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null;
1688+ var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options);
1689+ var validationResults = new global::System.Collections.Generic.List<global::System.ComponentModel.DataAnnotations.ValidationResult>();
1690+ var validationAttributes = new global::System.Collections.Generic.List<global::System.ComponentModel.DataAnnotations.ValidationAttribute>(1);
1691+
1692+ context.MemberName = "P1";
1693+ context.DisplayName = string.IsNullOrEmpty(name) ? "MyOptions.P1" : $"{name}.P1";
1694+ validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1);
1695+ if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1, context, validationResults, validationAttributes))
1696+ {
1697+ (builder ??= new()).AddResults(validationResults);
1698+ }
1699+
1700+ context.MemberName = "P2";
1701+ context.DisplayName = string.IsNullOrEmpty(name) ? "MyOptions.P2" : $"{name}.P2";
1702+ validationResults.Clear();
1703+ validationAttributes.Clear();
1704+ validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2);
1705+ if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P2, context, validationResults, validationAttributes))
1706+ {
1707+ (builder ??= new()).AddResults(validationResults);
1708+ }
1709+
1710+ context.MemberName = "P3";
1711+ context.DisplayName = string.IsNullOrEmpty(name) ? "MyOptions.P3" : $"{name}.P3";
1712+ validationResults.Clear();
1713+ validationAttributes.Clear();
1714+ validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A3);
1715+ if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P3, context, validationResults, validationAttributes))
1716+ {
1717+ (builder ??= new()).AddResults(validationResults);
1718+ }
1719+
1720+ context.MemberName = "P4";
1721+ context.DisplayName = string.IsNullOrEmpty(name) ? "MyOptions.P4" : $"{name}.P4";
1722+ validationResults.Clear();
1723+ validationAttributes.Clear();
1724+ validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A4);
1725+ if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P4, context, validationResults, validationAttributes))
1726+ {
1727+ (builder ??= new()).AddResults(validationResults);
1728+ }
1729+
1730+ return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build();
1731+ }
1732+ }
1733+ }
1734+ namespace __OptionValidationStaticInstances
1735+ {
1736+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")]
1737+ file static class __Attributes
1738+ {
1739+ internal static readonly global::System.ComponentModel.DataAnnotations.RequiredAttribute A1 = new global::System.ComponentModel.DataAnnotations.RequiredAttribute();
1740+
1741+ internal static readonly global::System.ComponentModel.DataAnnotations.LengthAttribute A2 = new global::System.ComponentModel.DataAnnotations.LengthAttribute(
1742+ (int)10,
1743+ (int)20);
1744+
1745+ internal static readonly global::System.ComponentModel.DataAnnotations.AllowedValuesAttribute A3 = new global::System.ComponentModel.DataAnnotations.AllowedValuesAttribute(
1746+ (int)10, (int)20, (int)30);
1747+
1748+ internal static readonly global::System.ComponentModel.DataAnnotations.DeniedValuesAttribute A4 = new global::System.ComponentModel.DataAnnotations.DeniedValuesAttribute(
1749+ "One", "Ten", "Hundred");
1750+ }
1751+ }
1752+ namespace __OptionValidationStaticInstances
1753+ {
1754+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")]
1755+ file static class __Validators
1756+ {
1757+ }
1758+ }
1759+
1760+ """ ;
1761+ Assert . Equal ( generatedSource . Replace ( "\r \n " , "\n " ) , generatedSources [ 0 ] . SourceText . ToString ( ) . Replace ( "\r \n " , "\n " ) ) ;
1762+ }
1763+
16411764 private static CSharpCompilation CreateCompilationForOptionsSource ( string assemblyName , string source , string ? refAssemblyPath = null )
16421765 {
16431766 // Ensure the generated source compiles
@@ -1676,7 +1799,7 @@ private static CSharpCompilation CreateCompilationForOptionsSource(string assemb
16761799 refAssemblies . Add ( refAssembly ) ;
16771800 }
16781801
1679- return await RoslynTestUtils . RunGenerator ( new Generator ( ) , refAssemblies . ToArray ( ) , new List < string > { source } , includeBaseReferences : true , languageVersion ) . ConfigureAwait ( false ) ;
1802+ return await RoslynTestUtils . RunGenerator ( new OptionsValidatorGenerator ( ) , refAssemblies . ToArray ( ) , new List < string > { source } , includeBaseReferences : true , languageVersion ) . ConfigureAwait ( false ) ;
16801803 }
16811804
16821805 private static async Task < ( IReadOnlyList < Diagnostic > diagnostics , ImmutableArray < GeneratedSourceResult > generatedSources ) > RunGenerator (
@@ -1733,7 +1856,7 @@ private static CSharpCompilation CreateCompilationForOptionsSource(string assemb
17331856 assemblies . Add ( Assembly . GetAssembly ( typeof ( Microsoft . Extensions . Options . ValidateObjectMembersAttribute ) ) ! ) ;
17341857 }
17351858
1736- var result = await RoslynTestUtils . RunGenerator ( new Generator ( ) , assemblies . ToArray ( ) , new [ ] { text } )
1859+ var result = await RoslynTestUtils . RunGenerator ( new OptionsValidatorGenerator ( ) , assemblies . ToArray ( ) , new [ ] { text } )
17371860 . ConfigureAwait ( false ) ;
17381861
17391862 return result ;
0 commit comments