2
2
using System . Collections . Generic ;
3
3
using System . ComponentModel . DataAnnotations ;
4
4
using System . Linq ;
5
- using System . Runtime . CompilerServices ;
6
5
using Zeus . Shared . Exceptions ;
7
6
8
7
namespace Zeus . Shared . Validation
@@ -14,86 +13,36 @@ public static void EnsureValid(object instance)
14
13
if ( instance == null )
15
14
throw new ArgumentNullException ( nameof ( instance ) ) ;
16
15
17
- var results = new List < ValidationResult > ( ) ;
18
- if ( TryValidateRecursive ( instance , ref results ) )
16
+ var context = new ValidationContext ( instance ) ;
17
+ var validationResults = new List < ValidationResult > ( ) ;
18
+
19
+ if ( Validator . TryValidateObject ( instance , context , validationResults , validateAllProperties : true ) )
19
20
return ;
20
21
21
- var errors = results . Where ( s => ! string . IsNullOrEmpty ( s . ErrorMessage ) )
22
+ var flatResults = new List < ValidationResult > ( ) ;
23
+ Flatten ( validationResults , ref flatResults ) ;
24
+
25
+ var errors = flatResults . Where ( s => ! string . IsNullOrEmpty ( s . ErrorMessage ) )
22
26
. Select ( s => s . ErrorMessage ) ;
23
27
24
28
var errorMessage = string . Join ( ';' , errors ) ;
25
29
throw new ConfigurationException ( $ "Errors occured while validating object '{ instance . GetType ( ) . Name } ': { errorMessage } ") ;
26
30
}
27
31
28
- private static bool TryValidateRecursive ( object instance , ref List < ValidationResult > results )
32
+ private static void Flatten ( IEnumerable < ValidationResult > results , ref List < ValidationResult > output )
29
33
{
30
- if ( instance == null )
31
- throw new ArgumentNullException ( nameof ( instance ) ) ;
32
-
33
- if ( results == null )
34
- results = new List < ValidationResult > ( ) ;
35
-
36
- var validationContext = new ValidationContext ( instance ) ;
37
- var isValid = Validator . TryValidateObject ( instance , validationContext , results , validateAllProperties : true ) ;
34
+ if ( output == null )
35
+ output = new List < ValidationResult > ( ) ;
38
36
39
- var properties = instance . GetType ( )
40
- . GetProperties ( )
41
- . Where ( prop => prop . CanRead && prop . GetIndexParameters ( ) . Length == 0 )
42
- . Where ( prop => CanValidate ( prop . PropertyType ) )
43
- . ToArray ( ) ;
44
-
45
- foreach ( var property in properties )
37
+ foreach ( var result in results )
46
38
{
47
- var value = property . GetValue ( instance ) ;
48
- if ( value == null )
49
- continue ;
50
-
51
- var enumerable = value as IEnumerable < object > ?? new [ ] { value } ;
39
+ output . Add ( result ) ;
52
40
53
- foreach ( var toValidate in enumerable )
41
+ if ( result is CompositeValidationResult composite )
54
42
{
55
- var nestedResults = new List < ValidationResult > ( ) ;
56
- if ( TryValidateRecursive ( toValidate , ref nestedResults ) )
57
- {
58
- continue ;
59
- }
60
-
61
- isValid = false ;
62
-
63
- results . AddRange ( nestedResults
64
- . Select ( result => new ValidationResult (
65
- result . ErrorMessage , result . MemberNames
66
- . Select ( x => property . Name + '.' + x ) ) ) ) ;
43
+ Flatten ( composite . InnerResults , ref output ) ;
67
44
}
68
45
}
69
-
70
-
71
- return isValid ;
72
- }
73
-
74
- /// <summary>
75
- /// Returns whether the given <paramref name="type"/> can be validated
76
- /// </summary>
77
- [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
78
- private static bool CanValidate ( Type type )
79
- {
80
- while ( true )
81
- {
82
- if ( type == null )
83
- return false ;
84
-
85
- if ( type == typeof ( string ) )
86
- return false ;
87
-
88
- if ( type . IsValueType )
89
- return false ;
90
-
91
- if ( ! type . IsArray || ! type . HasElementType )
92
- return true ;
93
-
94
- var elementType = type . GetElementType ( ) ;
95
- type = elementType ;
96
- }
97
46
}
98
47
}
99
48
}
0 commit comments