@@ -495,6 +495,95 @@ public async Task Validate_RequiredOnPropertyShortCircuitsOtherValidations()
495495        Assert . Equal ( "The Password field is required." ,  error . Value . Single ( ) ) ; 
496496    } 
497497
498+     [ Fact ] 
499+     public  async  Task  Validate_IValidatableObject_WithZeroAndMultipleMemberNames_BehavesAsExpected ( ) 
500+     { 
501+         var  globalType  =  new  TestValidatableTypeInfo ( 
502+             typeof ( GlobalErrorObject ) , 
503+             [ ] ) ;  // no properties – nothing sets MemberName 
504+ 
505+         var  context  =  new  ValidateContext 
506+         { 
507+             ValidationOptions  =  new  TestValidationOptions ( new  Dictionary < Type ,  ValidatableTypeInfo > 
508+             { 
509+                 {  typeof ( GlobalErrorObject ) ,  globalType  } 
510+             } ) 
511+         } ; 
512+ 
513+         var  globalErrorInstance  =  new  GlobalErrorObject  {  Data  =  - 1  } ; 
514+         context . ValidationContext  =  new  ValidationContext ( globalErrorInstance ) ; 
515+ 
516+         await  globalType . ValidateAsync ( globalErrorInstance ,  context ,  default ) ; 
517+ 
518+         Assert . NotNull ( context . ValidationErrors ) ; 
519+         var  globalError  =  Assert . Single ( context . ValidationErrors ) ; 
520+         Assert . Equal ( string . Empty ,  globalError . Key ) ; 
521+         Assert . Equal ( "Data must be positive." ,  globalError . Value . Single ( ) ) ; 
522+ 
523+         var  multiType  =  new  TestValidatableTypeInfo ( 
524+             typeof ( MultiMemberErrorObject ) , 
525+             [ 
526+                 CreatePropertyInfo ( typeof ( MultiMemberErrorObject ) ,  typeof ( string ) ,  "FirstName" ,  "FirstName" ,  [ ] ) , 
527+                 CreatePropertyInfo ( typeof ( MultiMemberErrorObject ) ,  typeof ( string ) ,  "LastName" ,   "LastName" ,   [ ] ) 
528+             ] ) ; 
529+ 
530+         context . ValidationErrors  =  [ ] ; 
531+         context . ValidationOptions  =  new  TestValidationOptions ( new  Dictionary < Type ,  ValidatableTypeInfo > 
532+         { 
533+             {  typeof ( MultiMemberErrorObject ) ,  multiType  } 
534+         } ) ; 
535+ 
536+         var  multiErrorInstance  =  new  MultiMemberErrorObject  {  FirstName  =  "" ,  LastName  =  ""  } ; 
537+         context . ValidationContext  =  new  ValidationContext ( multiErrorInstance ) ; 
538+ 
539+         await  multiType . ValidateAsync ( multiErrorInstance ,  context ,  default ) ; 
540+ 
541+         Assert . NotNull ( context . ValidationErrors ) ; 
542+         Assert . Collection ( context . ValidationErrors , 
543+             kvp => 
544+             { 
545+                 Assert . Equal ( "FirstName" ,  kvp . Key ) ; 
546+                 Assert . Equal ( "FirstName and LastName are required." ,  kvp . Value . First ( ) ) ; 
547+             } , 
548+             kvp => 
549+             { 
550+                 Assert . Equal ( "LastName" ,  kvp . Key ) ; 
551+                 Assert . Equal ( "FirstName and LastName are required." ,  kvp . Value . First ( ) ) ; 
552+             } ) ; 
553+     } 
554+ 
555+     // Returns no member names to validate https://github.com/dotnet/aspnetcore/issues/61739 
556+     private  class  GlobalErrorObject  :  IValidatableObject 
557+     { 
558+         public  int  Data  {  get ;  set ;  } 
559+ 
560+         public  IEnumerable < ValidationResult >  Validate ( ValidationContext  validationContext ) 
561+         { 
562+             if  ( Data  <=  0 ) 
563+             { 
564+                 yield  return  new  ValidationResult ( "Data must be positive." ) ; 
565+             } 
566+         } 
567+     } 
568+ 
569+     // Returns multiple member names to validate https://github.com/dotnet/aspnetcore/issues/61739 
570+     private  class  MultiMemberErrorObject  :  IValidatableObject 
571+     { 
572+         public  string ?  FirstName  {  get ;  set ;  } 
573+         public  string ?  LastName  {  get ;  set ;  } 
574+ 
575+         public  IEnumerable < ValidationResult >  Validate ( ValidationContext  validationContext ) 
576+         { 
577+             if  ( string . IsNullOrEmpty ( FirstName )  ||  string . IsNullOrEmpty ( LastName ) ) 
578+             { 
579+                 // MULTIPLE member names 
580+                 yield  return  new  ValidationResult ( 
581+                     "FirstName and LastName are required." , 
582+                     [ nameof ( FirstName ) ,  nameof ( LastName ) ] ) ; 
583+             } 
584+         } 
585+     } 
586+ 
498587    private  ValidatablePropertyInfo  CreatePropertyInfo ( 
499588        Type  containingType , 
500589        Type  propertyType , 
@@ -534,7 +623,7 @@ public IEnumerable<ValidationResult> Validate(ValidationContext validationContex
534623        { 
535624            if  ( Salary  <  0 ) 
536625            { 
537-                 yield  return  new  ValidationResult ( "Salary must be a positive value." ,  new [ ]   {   nameof ( Salary )   } ) ; 
626+                 yield  return  new  ValidationResult ( "Salary must be a positive value." ,  [ " Salary" ] ) ; 
538627            } 
539628        } 
540629    } 
0 commit comments