@@ -12,57 +12,85 @@ namespace NuGet.Services.Validation.Orchestrator
1212{
1313 public class ValidatorProvider : IValidatorProvider
1414 {
15+ /// <summary>
16+ /// This is a cache of all of the <see cref="IValidator"/> and <see cref="IProcessor"/> implementations
17+ /// available.
18+ /// </summary>
19+ private static EvaluatedTypes _evaluatedTypes ;
20+ private static object _evaluatedTypesLock = new object ( ) ;
21+
1522 private readonly IServiceProvider _serviceProvider ;
1623 private readonly ILogger < ValidatorProvider > _logger ;
17- private readonly Dictionary < string , Type > _validatorTypes ;
18- private readonly Dictionary < string , Type > _processorTypes ;
1924
2025 public ValidatorProvider ( IServiceProvider serviceProvider , ILogger < ValidatorProvider > logger )
2126 {
2227 _serviceProvider = serviceProvider ?? throw new ArgumentNullException ( nameof ( serviceProvider ) ) ;
2328 _logger = logger ?? throw new ArgumentNullException ( nameof ( logger ) ) ;
2429
25- using ( _logger . BeginScope ( "Enumerating all IValidator implementations" ) )
30+ InitializeEvaluatedTypes ( Assembly . GetCallingAssembly ( ) ) ;
31+ }
32+
33+ /// <summary>
34+ /// Discovers all <see cref="IValidator"/> and <see cref="IProcessor"/> types available and caches the result.
35+ /// </summary>
36+ private void InitializeEvaluatedTypes ( Assembly callingAssembly )
37+ {
38+ if ( _evaluatedTypes != null )
39+ {
40+ return ;
41+ }
42+
43+ lock ( _evaluatedTypesLock )
2644 {
27- _logger . LogTrace ( "Before enumeration" ) ;
28- IEnumerable < Type > candidateTypes = GetCandidateTypes ( Assembly . GetCallingAssembly ( ) ) ;
29-
30- _validatorTypes = candidateTypes
31- . Where ( type => typeof ( IValidator ) . IsAssignableFrom ( type )
32- && type != typeof ( IValidator )
33- && type != typeof ( IProcessor ) )
34- . ToDictionary ( type => type . Name ) ;
35-
36- _processorTypes = _validatorTypes
37- . Values
38- . Where ( IsProcessor )
39- . ToDictionary ( type => type . Name ) ;
40-
41- _logger . LogTrace ( "After enumeration, got {NumImplementations} implementations: {TypeNames}" ,
42- _validatorTypes . Count ,
43- _validatorTypes . Keys ) ;
45+ if ( _evaluatedTypes != null )
46+ {
47+ return ;
48+ }
49+
50+ using ( _logger . BeginScope ( "Enumerating all IValidator implementations" ) )
51+ {
52+ _logger . LogTrace ( "Before enumeration" ) ;
53+ IEnumerable < Type > candidateTypes = GetCandidateTypes ( callingAssembly ) ;
54+
55+ var validatorTypes = candidateTypes
56+ . Where ( type => typeof ( IValidator ) . IsAssignableFrom ( type )
57+ && type != typeof ( IValidator )
58+ && type != typeof ( IProcessor ) )
59+ . ToDictionary ( type => type . Name ) ;
60+
61+ var processorTypes = validatorTypes
62+ . Values
63+ . Where ( IsProcessorType )
64+ . ToDictionary ( type => type . Name ) ;
65+
66+ _logger . LogTrace ( "After enumeration, got {NumImplementations} implementations: {TypeNames}" ,
67+ validatorTypes . Count ,
68+ validatorTypes . Keys ) ;
69+
70+ _evaluatedTypes = new EvaluatedTypes ( validatorTypes , processorTypes ) ;
71+ }
4472 }
4573 }
4674
4775 public bool IsValidator ( string validatorName )
4876 {
4977 validatorName = validatorName ?? throw new ArgumentNullException ( nameof ( validatorName ) ) ;
5078
51- return _validatorTypes . ContainsKey ( validatorName ) ;
79+ return _evaluatedTypes . ValidatorTypes . ContainsKey ( validatorName ) ;
5280 }
5381
5482 public bool IsProcessor ( string validatorName )
5583 {
5684 validatorName = validatorName ?? throw new ArgumentNullException ( nameof ( validatorName ) ) ;
5785
58- return _processorTypes . ContainsKey ( validatorName ) ;
86+ return _evaluatedTypes . ProcessorTypes . ContainsKey ( validatorName ) ;
5987 }
6088
6189 public IValidator GetValidator ( string validatorName )
6290 {
6391 validatorName = validatorName ?? throw new ArgumentNullException ( nameof ( validatorName ) ) ;
6492
65- if ( _validatorTypes . TryGetValue ( validatorName , out Type validatorType ) )
93+ if ( _evaluatedTypes . ValidatorTypes . TryGetValue ( validatorName , out Type validatorType ) )
6694 {
6795 return ( IValidator ) _serviceProvider . GetRequiredService ( validatorType ) ;
6896 }
@@ -82,9 +110,23 @@ private static IEnumerable<Type> GetCandidateTypes(Assembly callingAssembly)
82110 return candidateTypes ;
83111 }
84112
85- private static bool IsProcessor ( Type type )
113+ private static bool IsProcessorType ( Type type )
86114 {
87115 return typeof ( IProcessor ) . IsAssignableFrom ( type ) ;
88116 }
117+
118+ private class EvaluatedTypes
119+ {
120+ public EvaluatedTypes (
121+ IReadOnlyDictionary < string , Type > validatorTypes ,
122+ IReadOnlyDictionary < string , Type > processorTypes )
123+ {
124+ ValidatorTypes = validatorTypes ?? throw new ArgumentNullException ( nameof ( validatorTypes ) ) ;
125+ ProcessorTypes = processorTypes ?? throw new ArgumentNullException ( nameof ( validatorTypes ) ) ;
126+ }
127+
128+ public IReadOnlyDictionary < string , Type > ValidatorTypes { get ; }
129+ public IReadOnlyDictionary < string , Type > ProcessorTypes { get ; }
130+ }
89131 }
90132}
0 commit comments