7
7
using System ;
8
8
using System . Collections . Generic ;
9
9
using System . Linq ;
10
+ using System . Text ;
10
11
using Microsoft . AspNetCore . Hosting ;
11
12
using Microsoft . Extensions . DependencyInjection ;
12
13
using Microsoft . Extensions . Hosting ;
@@ -98,11 +99,16 @@ public static IServiceCollection CreateChildContainer(this IServiceProvider serv
98
99
else if ( services . All ( s => s . Lifetime == ServiceLifetime . Singleton ) )
99
100
{
100
101
// We can resolve them from the main container.
101
- var instances = serviceProvider . GetServices ( services . Key ) ;
102
+ // Materialize services and instances to arrays once.
103
+ var servicesArray = services . ToArray ( ) ;
104
+ var instancesArray = serviceProvider . GetServices ( services . Key ) ? . ToArray ( ) ?? Array . Empty < object > ( ) ;
102
105
103
- for ( var i = 0 ; i < services . Count ( ) ; i ++ )
106
+ // Validate counts
107
+ ValidateServiceAndInstanceCounts ( servicesArray , instancesArray , services . Key ) ;
108
+
109
+ for ( var i = 0 ; i < servicesArray . Length ; i ++ )
104
110
{
105
- clonedCollection . CloneSingleton ( services . ElementAt ( i ) , instances . ElementAt ( i ) ) ;
111
+ clonedCollection . CloneSingleton ( servicesArray [ i ] , instancesArray [ i ] ) ;
106
112
}
107
113
}
108
114
@@ -112,25 +118,46 @@ public static IServiceCollection CreateChildContainer(this IServiceProvider serv
112
118
// We need a service scope to resolve them.
113
119
using var scope = serviceProvider . CreateScope ( ) ;
114
120
115
- var instances = scope . ServiceProvider . GetServices ( services . Key ) ;
121
+ // Materialize services and instances to arrays once.
122
+ var servicesArray = services . ToArray ( ) ;
123
+ var instancesArray = scope . ServiceProvider . GetServices ( services . Key ) ? . ToArray ( ) ?? Array . Empty < object > ( ) ;
124
+
125
+ ValidateServiceAndInstanceCounts ( servicesArray , instancesArray , services . Key ) ;
116
126
117
127
// Then we only keep singleton instances.
118
- for ( var i = 0 ; i < services . Count ( ) ; i ++ )
128
+ for ( var i = 0 ; i < servicesArray . Length ; i ++ )
119
129
{
120
- if ( services . ElementAt ( i ) . Lifetime == ServiceLifetime . Singleton )
130
+ if ( servicesArray [ i ] . Lifetime == ServiceLifetime . Singleton )
121
131
{
122
- clonedCollection . CloneSingleton ( services . ElementAt ( i ) , instances . ElementAt ( i ) ) ;
132
+ clonedCollection . CloneSingleton ( servicesArray [ i ] , instancesArray [ i ] ) ;
123
133
}
124
134
else
125
135
{
126
- clonedCollection . Add ( services . ElementAt ( i ) ) ;
136
+ clonedCollection . Add ( servicesArray [ i ] ) ;
127
137
}
128
138
}
129
139
}
130
140
}
131
141
132
142
return clonedCollection ;
133
143
}
144
+
145
+ private static void ValidateServiceAndInstanceCounts < TService , TInstance > ( TService [ ] servicesArray , TInstance [ ] instancesArray , Type serviceType )
146
+ {
147
+ if ( servicesArray . Length != instancesArray . Length )
148
+ {
149
+ var message = $ """
150
+ Mismatch detected for type { serviceType } :
151
+ services.Count = { servicesArray . Length } , instances.Count = { instancesArray . Length }
152
+ Services:
153
+ { string . Join ( ",\n \t " , servicesArray . Select ( s => s . ToString ( ) ) ) }
154
+ Instances:
155
+ { string . Join ( ",\n \t " , instancesArray . Select ( i => i ? . GetType ( ) ? . ToString ( ) ?? "null" ) ) }
156
+ """ ;
157
+
158
+ throw new InvalidOperationException ( message ) ;
159
+ }
160
+ }
134
161
}
135
162
136
163
internal static class ServiceCollectionExtensions
0 commit comments