@@ -261,6 +261,43 @@ public void MetadataTypeIValidatableObject_Ok()
261261 Assert . Equal ( "两次密码必须一致。" , message ) ;
262262 }
263263
264+ [ Fact ]
265+ public async Task MetadataTypeIValidateCollection_Ok ( )
266+ {
267+ var model = new Dummy2 ( ) { Value1 = 0 , Value2 = 0 } ;
268+ var cut = Context . RenderComponent < ValidateForm > ( pb =>
269+ {
270+ pb . Add ( a => a . Model , model ) ;
271+ pb . AddChildContent < MockInput < int > > ( pb =>
272+ {
273+ pb . Add ( a => a . Value , model . Value1 ) ;
274+ pb . Add ( a => a . ValueExpression , Utility . GenerateValueExpression ( model , "Value1" , typeof ( int ) ) ) ;
275+ } ) ;
276+ pb . AddChildContent < MockInput < int > > ( pb =>
277+ {
278+ pb . Add ( a => a . Value , model . Value2 ) ;
279+ pb . Add ( a => a . ValueExpression , Utility . GenerateValueExpression ( model , "Value2" , typeof ( int ) ) ) ;
280+ } ) ;
281+ } ) ;
282+ var form = cut . Find ( "form" ) ;
283+ await cut . InvokeAsync ( ( ) => form . Submit ( ) ) ;
284+ var input = cut . FindComponent < MockInput < int > > ( ) ;
285+ var all = cut . FindComponents < MockInput < int > > ( ) ;
286+ var input2 = all [ all . Count - 1 ] ;
287+ Assert . Null ( input . Instance . GetErrorMessage ( ) ) ;
288+ Assert . Equal ( "Value2 必须大于 0" , input2 . Instance . GetErrorMessage ( ) ) ;
289+
290+ model . Value1 = 0 ;
291+ model . Value2 = 2 ;
292+ cut . SetParametersAndRender ( pb =>
293+ {
294+ pb . Add ( a => a . Model , model ) ;
295+ } ) ;
296+ await cut . InvokeAsync ( ( ) => form . Submit ( ) ) ;
297+ Assert . Equal ( "Value1 必须大于 Value2" , input . Instance . GetErrorMessage ( ) ) ;
298+ Assert . Equal ( "Value1 必须大于 Value2" , input2 . Instance . GetErrorMessage ( ) ) ;
299+ }
300+
264301 [ Fact ]
265302 public void Validate_Class_Ok ( )
266303 {
@@ -698,6 +735,7 @@ private class Dummy
698735 public string ? File { get ; set ; }
699736
700737 public string ? Password1 { get ; set ; }
738+
701739 public string ? Password2 { get ; set ; }
702740 }
703741
@@ -712,13 +750,68 @@ public IEnumerable<ValidationResult> Validate(ValidationContext validationContex
712750 if ( validationContext . ObjectInstance is Dummy dy )
713751 {
714752 if ( ! string . Equals ( dy . Password1 , dy . Password2 , StringComparison . InvariantCultureIgnoreCase ) )
715- result . Add ( new ValidationResult ( "两次密码必须一致。" ,
716- [ nameof ( Dummy . Password1 ) , nameof ( Dummy . Password2 ) ] ) ) ;
753+ {
754+ result . Add ( new ValidationResult ( "两次密码必须一致。" , [ nameof ( Dummy . Password1 ) , nameof ( Dummy . Password2 ) ] ) ) ;
755+ }
717756 }
718757 return result ;
719758 }
720759 }
721760
761+ [ MetadataType ( typeof ( Dummy2MetadataCollection ) ) ]
762+ private class Dummy2
763+ {
764+ public int Value1 { get ; set ; }
765+
766+ public int Value2 { get ; set ; }
767+ }
768+
769+ public class Dummy2MetadataCollection : IValidateCollection
770+ {
771+ [ Required ]
772+ public int Value1 { get ; set ; }
773+
774+ [ CustomValidation ( typeof ( Dummy2MetadataCollection ) , nameof ( CustomValidate ) , ErrorMessage = "{0} 必须大于 0" ) ]
775+ [ Required ]
776+ public int Value2 { get ; set ; }
777+
778+ private readonly List < string > _validMemberNames = [ ] ;
779+
780+ public List < string > GetValidMemberNames ( ) => _validMemberNames ;
781+
782+ private readonly List < ValidationResult > _invalidMemberNames = [ ] ;
783+
784+ public List < ValidationResult > GetInvalidMemberNames ( ) => _invalidMemberNames ;
785+
786+ public IEnumerable < ValidationResult > Validate ( ValidationContext validationContext )
787+ {
788+ _invalidMemberNames . Clear ( ) ;
789+ _validMemberNames . Clear ( ) ;
790+ if ( validationContext . ObjectInstance is Dummy2 dummy )
791+ {
792+ if ( dummy . Value1 < dummy . Value2 )
793+ {
794+ _invalidMemberNames . Add ( new ValidationResult ( "Value1 必须大于 Value2" , [ nameof ( Dummy2 . Value1 ) , nameof ( Dummy2 . Value2 ) ] ) ) ;
795+ }
796+ else
797+ {
798+ _validMemberNames . AddRange ( [ nameof ( Dummy2 . Value1 ) , nameof ( Dummy2 . Value2 ) ] ) ;
799+ }
800+ }
801+ return _invalidMemberNames ;
802+ }
803+
804+ public static ValidationResult ? CustomValidate ( object value , ValidationContext context )
805+ {
806+ ValidationResult ? ret = null ;
807+ if ( value is int v && v < 1 )
808+ {
809+ ret = new ValidationResult ( "Value2 必须大于 0" , [ "Value2" ] ) ;
810+ }
811+ return ret ;
812+ }
813+ }
814+
722815 private class MockFoo
723816 {
724817 [ Required ( ErrorMessage = "{0} is Required" ) ]
@@ -803,13 +896,13 @@ public IEnumerable<ValidationResult> Validate(ValidationContext validationContex
803896 /// <inheritdoc/>
804897 /// </summary>
805898 /// <returns></returns>
806- public List < string > ValidMemberNames ( ) => _validMemberNames ;
899+ public List < string > GetValidMemberNames ( ) => _validMemberNames ;
807900
808901 /// <summary>
809902 /// <inheritdoc/>
810903 /// </summary>
811904 /// <returns></returns>
812- public List < ValidationResult > InvalidMemberNames ( ) => _invalidMemberNames ;
905+ public List < ValidationResult > GetInvalidMemberNames ( ) => _invalidMemberNames ;
813906 }
814907
815908 private class MockInput < TValue > : BootstrapInput < TValue >
0 commit comments