11using Microsoft . Extensions . DependencyInjection ;
22using Ninject . Syntax ;
33using System ;
4+ using System . Collections ;
5+ using System . Collections . Generic ;
6+ using System . Linq ;
7+ using System . Reflection ;
48using Ninject . Planning . Bindings ;
59
610namespace Ninject . Web . AspNetCore
@@ -24,6 +28,7 @@ public class NinjectServiceProvider : IServiceProvider, ISupportRequiredService,
2428 , IKeyedServiceProvider
2529#endif
2630 {
31+ private static readonly MethodInfo EnumerableCastMethod = typeof ( Enumerable ) . GetMethod ( nameof ( Enumerable . Cast ) ) ;
2732 private readonly IResolutionRoot _resolutionRoot ;
2833 private readonly IServiceScope _scope ;
2934
@@ -35,13 +40,35 @@ public NinjectServiceProvider(IResolutionRoot resolutionRoot, IServiceScope scop
3540
3641 public object GetRequiredService ( Type serviceType )
3742 {
38- var result = _resolutionRoot . Get ( serviceType ) ;
39- return result ;
43+ object result = null ;
44+ if ( ! IsListType ( serviceType , out var elementType ) )
45+ {
46+ return _resolutionRoot . Get ( serviceType ) ;
47+ }
48+ else
49+ {
50+ // Ninject is not evaluating metadata constraint when resolving a IEnumerable<T>, see KernelBase.UpdateRequest
51+ // Therefore, need to implement a workaround to not instantiate here bindings with servicekey
52+ return ConvertToTypedEnumerable ( elementType ,
53+ _resolutionRoot . GetAll ( elementType , metadata => ! HasServiceKeyMetadata ( metadata ) ) ) ;
54+ }
4055 }
4156
4257 public object GetService ( Type serviceType )
4358 {
44- var result = _resolutionRoot . TryGet ( serviceType ) ;
59+ object result = null ;
60+ if ( ! IsListType ( serviceType , out var elementType ) )
61+ {
62+ result = _resolutionRoot . TryGet ( serviceType ) ;
63+ }
64+ else
65+ {
66+ // Ninject is not evaluating metadata constraint when resolving a IEnumerable<T>, see KernelBase.UpdateRequest
67+ // Therefore, need to implement a workaround to not instantiate here bindings with servicekey
68+ result = ConvertToTypedEnumerable ( elementType ,
69+ _resolutionRoot . GetAll ( elementType , metadata => ! HasServiceKeyMetadata ( metadata ) ) ) ;
70+ }
71+
4572 return result ;
4673 }
4774
@@ -53,19 +80,88 @@ public void Dispose()
5380#if NET8_0_OR_GREATER
5481 public object GetKeyedService ( Type serviceType , object serviceKey )
5582 {
56- var result = _resolutionRoot . TryGet ( serviceType , metadata => DoesMetadataMatchServiceKey ( serviceKey , metadata ) ) ;
83+ object result = null ;
84+ if ( ! IsListType ( serviceType , out var elementType ) )
85+ {
86+ result = _resolutionRoot . TryGet ( serviceType ,
87+ metadata => DoesMetadataMatchServiceKey ( serviceKey , metadata ) ) ;
88+ }
89+ else
90+ {
91+ // Ninject is not evaluating metadata constraint when resolving a IEnumerable<T>, see KernelBase.UpdateRequest
92+ // Therefore, need to implement a workaround to not instantiate here bindings with a different servicekey value
93+ result = ConvertToTypedEnumerable ( elementType ,
94+ _resolutionRoot . GetAll ( elementType , metadata => DoesMetadataMatchServiceKey ( serviceKey , metadata ) ) ) ;
95+ }
96+
5797 return result ;
5898 }
5999
60100 public object GetRequiredKeyedService ( Type serviceType , object serviceKey )
61101 {
62- return _resolutionRoot . Get ( serviceType , metadata => DoesMetadataMatchServiceKey ( serviceKey , metadata ) ) ;
102+ if ( ! IsListType ( serviceType , out var elementType ) )
103+ {
104+ return _resolutionRoot . Get ( serviceType , metadata => DoesMetadataMatchServiceKey ( serviceKey , metadata ) ) ;
105+ }
106+ else
107+ {
108+ // Ninject is not evaluating metadata constraint when resolving a IEnumerable<T>, see KernelBase.UpdateRequest
109+ // Therefore, need to implement a workaround to not instantiate here bindings with a different servicekey value
110+ return ConvertToTypedEnumerable ( elementType ,
111+ _resolutionRoot . GetAll ( elementType , metadata => DoesMetadataMatchServiceKey ( serviceKey , metadata ) ) . ToList ( ) ) ;
112+ }
63113 }
64114
65115 private static bool DoesMetadataMatchServiceKey ( object serviceKey , IBindingMetadata metadata )
66116 {
67117 return metadata . Get < ServiceKey > ( nameof ( ServiceKey ) ) ? . Key == serviceKey ;
68118 }
69119#endif
120+
121+ private static bool HasServiceKeyMetadata ( IBindingMetadata metadata )
122+ {
123+ return metadata . Has ( nameof ( ServiceKey ) ) ;
124+ }
125+
126+ /// <summary>
127+ /// This method extracts the elementtype in the same way as Ninject does
128+ /// in KernelBase.Resolve
129+ /// </summary>
130+ private static bool IsListType ( Type type , out Type elementType )
131+ {
132+ if ( type . IsArray )
133+ {
134+ elementType = type . GetElementType ( ) ;
135+ return true ;
136+ }
137+
138+ if ( type . IsGenericType )
139+ {
140+ Type genericTypeDefinition = type . GetGenericTypeDefinition ( ) ;
141+ if ( genericTypeDefinition == typeof ( List < > ) || genericTypeDefinition == typeof ( IList < > ) ||
142+ genericTypeDefinition == typeof ( ICollection < > ) )
143+ {
144+ elementType = type . GenericTypeArguments [ 0 ] ;
145+ return true ;
146+ }
147+
148+ if ( genericTypeDefinition == typeof ( IEnumerable < > ) )
149+ {
150+ elementType = type . GenericTypeArguments [ 0 ] ;
151+ return true ;
152+ }
153+ }
154+
155+ elementType = null ;
156+ return false ;
157+ }
158+
159+ private static object ConvertToTypedEnumerable ( Type elementType , IEnumerable < object > objectList )
160+ {
161+ var castMethod = EnumerableCastMethod . MakeGenericMethod ( elementType ) ;
162+ var result = ( IEnumerable ) castMethod . Invoke ( null , new object [ ] { objectList } ) ;
163+ return result ;
164+ }
165+
70166 }
71167}
0 commit comments