Skip to content

Commit f30ada7

Browse files
refactor to remove code duplication in ServiceCollectionAdapter
1 parent dd9919e commit f30ada7

File tree

5 files changed

+111
-44
lines changed

5 files changed

+111
-44
lines changed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using System;
2+
using Microsoft.Extensions.DependencyInjection;
3+
4+
namespace Ninject.Web.AspNetCore
5+
{
6+
/// <summary>
7+
/// This ServiceDescriptorAdapter is used when ServiceDescriptor.IsKeyedService == false
8+
/// This was always the case before .NET 8.0
9+
/// </summary>
10+
public class DefaultDescriptorAdapter : IDescriptorAdapter
11+
{
12+
private ServiceDescriptor _descriptor;
13+
14+
public DefaultDescriptorAdapter(ServiceDescriptor descriptor)
15+
{
16+
_descriptor = descriptor;
17+
}
18+
19+
public Type ImplementationType => _descriptor.ImplementationType;
20+
public object ImplementationInstance => _descriptor.ImplementationInstance;
21+
public bool UseServiceFactory => _descriptor.ImplementationFactory != null;
22+
public object InstantiateFromServiceFactory(IServiceProvider provider)
23+
{
24+
return _descriptor.ImplementationFactory(provider);
25+
}
26+
public ServiceLifetime Lifetime => _descriptor.Lifetime;
27+
}
28+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
using System;
2+
using Microsoft.Extensions.DependencyInjection;
3+
4+
namespace Ninject.Web.AspNetCore
5+
{
6+
/// <summary>
7+
/// This interface allows to handle the differences between keyed and non keyed implementation instruction
8+
/// on ServiceDescriptors
9+
/// </summary>
10+
public interface IDescriptorAdapter
11+
{
12+
/// <summary>
13+
/// Returns the type to instantiate if instantiation should be done by type.
14+
/// </summary>
15+
Type ImplementationType { get; }
16+
17+
/// <summary>
18+
/// Returns the instance if a specific instance is configured on the descriptor
19+
/// </summary>
20+
object ImplementationInstance { get; }
21+
22+
/// <summary>
23+
/// Returns true, if a service factory is configured on the descriptor
24+
/// </summary>
25+
bool UseServiceFactory { get; }
26+
27+
/// <summary>
28+
/// If UseServiceFactory returns true, use this method to instantiate via factory.
29+
/// </summary>
30+
object InstantiateFromServiceFactory(IServiceProvider provider);
31+
32+
/// <summary>
33+
/// The lifetime coonfigured for the service descriptor
34+
/// </summary>
35+
ServiceLifetime Lifetime { get; }
36+
}
37+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using System;
2+
using Microsoft.Extensions.DependencyInjection;
3+
4+
namespace Ninject.Web.AspNetCore
5+
{
6+
#if NET8_0_OR_GREATER
7+
/// <summary>
8+
/// This ServiceDescriptorAdapter is used when ServiceDescriptor.IsKeyedService == true
9+
/// </summary>
10+
public class KeyedDescriptorAdapter : IDescriptorAdapter
11+
{
12+
13+
private ServiceDescriptor _descriptor;
14+
15+
public KeyedDescriptorAdapter(ServiceDescriptor descriptor)
16+
{
17+
_descriptor = descriptor;
18+
}
19+
20+
public Type ImplementationType => _descriptor.KeyedImplementationType;
21+
public object ImplementationInstance => _descriptor.KeyedImplementationInstance;
22+
public bool UseServiceFactory => _descriptor.KeyedImplementationFactory != null;
23+
public object InstantiateFromServiceFactory(IServiceProvider provider)
24+
{
25+
return _descriptor.KeyedImplementationFactory(provider, _descriptor.ServiceKey);
26+
}
27+
28+
public ServiceLifetime Lifetime => _descriptor.Lifetime;
29+
}
30+
#endif
31+
}

src/Ninject.Web.AspNetCore/ServiceCollectionAdapter.cs

Lines changed: 12 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -55,23 +55,23 @@ private IBindingWithOrOnSyntax<T> ConfigureImplementationAndLifecycle<T>(
5555
ServiceDescriptor descriptor,
5656
BindingIndex bindingIndex) where T : class
5757
{
58-
IBindingNamedWithOrOnSyntax<T> result;
58+
IDescriptorAdapter adapter;
5959
#if NET8_0_OR_GREATER
6060
if (descriptor.IsKeyedService)
6161
{
62-
result = ConfigureImplementationAndLifecycleKeyed(bindingToSyntax, descriptor);
62+
adapter = new KeyedDescriptorAdapter(descriptor);
6363
}
6464
#endif
6565
#if NET8_0_OR_GREATER
6666
else
6767
{
6868
#endif
69-
result = ConfigureImplementationAndLifecycleNonKeyed(bindingToSyntax, descriptor);
69+
adapter = new DefaultDescriptorAdapter(descriptor);
7070
#if NET8_0_OR_GREATER
7171
}
7272
#endif
7373

74-
var resultWithMetadata = result
74+
var resultWithMetadata = ConfigureImplementationAndLifecycleWithAdapter(bindingToSyntax, adapter)
7575
.WithMetadata(nameof(ServiceDescriptor), descriptor)
7676
.WithMetadata(nameof(BindingIndex), bindingIndex.Next(descriptor.ServiceType));
7777

@@ -84,15 +84,15 @@ private IBindingWithOrOnSyntax<T> ConfigureImplementationAndLifecycle<T>(
8484
return resultWithMetadata;
8585
}
8686

87-
private IBindingNamedWithOrOnSyntax<T> ConfigureImplementationAndLifecycleNonKeyed<T>(IBindingToSyntax<T> bindingToSyntax,
88-
ServiceDescriptor descriptor) where T : class
87+
private IBindingNamedWithOrOnSyntax<T> ConfigureImplementationAndLifecycleWithAdapter<T>(IBindingToSyntax<T> bindingToSyntax,
88+
IDescriptorAdapter adapter) where T : class
8989
{
9090
IBindingNamedWithOrOnSyntax<T> result;
91-
if (descriptor.ImplementationType != null)
91+
if (adapter.ImplementationType != null)
9292
{
93-
result = ConfigureLifecycle(bindingToSyntax.To(descriptor.ImplementationType), descriptor.Lifetime);
93+
result = ConfigureLifecycle(bindingToSyntax.To(adapter.ImplementationType), adapter.Lifetime);
9494
}
95-
else if (descriptor.ImplementationFactory != null)
95+
else if (adapter.UseServiceFactory)
9696
{
9797

9898
result = ConfigureLifecycle(bindingToSyntax.ToMethod(context
@@ -102,50 +102,18 @@ private IBindingNamedWithOrOnSyntax<T> ConfigureImplementationAndLifecycleNonKey
102102
// correct _scoped_ IServiceProvider is used. Fall back to root IServiceProvider when not created
103103
// through a NinjectServiceProvider (some tests do this to prove a point)
104104
var scopeProvider = context.GetServiceProviderScopeParameter()?.SourceServiceProvider ?? context.Kernel.Get<IServiceProvider>();
105-
return descriptor.ImplementationFactory(scopeProvider) as T;
106-
}), descriptor.Lifetime);
105+
return adapter.InstantiateFromServiceFactory(scopeProvider) as T;
106+
}), adapter.Lifetime);
107107
}
108108
else
109109
{
110110
// use ToMethod here as ToConstant has the wrong return type.
111-
result = bindingToSyntax.ToMethod(context => descriptor.ImplementationInstance as T).InSingletonScope();
111+
result = bindingToSyntax.ToMethod(context => adapter.ImplementationInstance as T).InSingletonScope();
112112
}
113113

114114
return result;
115115
}
116116

117-
#if NET8_0_OR_GREATER
118-
private IBindingNamedWithOrOnSyntax<T> ConfigureImplementationAndLifecycleKeyed<T>(IBindingToSyntax<T> bindingToSyntax,
119-
ServiceDescriptor descriptor) where T : class
120-
{
121-
IBindingNamedWithOrOnSyntax<T> result;
122-
if (descriptor.KeyedImplementationType != null)
123-
{
124-
result = ConfigureLifecycle(bindingToSyntax.To(descriptor.KeyedImplementationType), descriptor.Lifetime);
125-
}
126-
else if (descriptor.KeyedImplementationFactory != null)
127-
{
128-
129-
result = ConfigureLifecycle(bindingToSyntax.ToMethod(context
130-
=>
131-
{
132-
// When resolved through the ServiceProviderScopeResolutionRoot which adds this parameter, the
133-
// correct _scoped_ IServiceProvider is used. Fall back to root IServiceProvider when not created
134-
// through a NinjectServiceProvider (some tests do this to prove a point)
135-
var scopeProvider = context.GetServiceProviderScopeParameter()?.SourceServiceProvider ?? context.Kernel.Get<IServiceProvider>();
136-
return descriptor.KeyedImplementationFactory(scopeProvider, descriptor.ServiceKey) as T;
137-
}), descriptor.Lifetime);
138-
}
139-
else
140-
{
141-
// use ToMethod here as ToConstant has the wrong return type.
142-
result = bindingToSyntax.ToMethod(context => descriptor.KeyedImplementationInstance as T).InSingletonScope();
143-
}
144-
145-
return result;
146-
}
147-
#endif
148-
149117
private IBindingNamedWithOrOnSyntax<T> ConfigureLifecycle<T>(
150118
IBindingInSyntax<T> bindingInSyntax,
151119
ServiceLifetime lifecycleKind)

src/Ninject.Web.AspNetCore/ServiceKey.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ namespace Ninject.Web.AspNetCore
55

66
#if NET8_0_OR_GREATER
77

8+
/// <summary>
9+
/// Used to store ServiceDescriptor.ServiceKey as metadata of the Ninject binding.
10+
/// </summary>
811
public class ServiceKey
912
{
1013
public object Key { get; }

0 commit comments

Comments
 (0)