Skip to content

Commit 31fa72c

Browse files
CopilotAGiorgetti
andcommitted
Fix: lifetime check methods return false for unregistered services instead of throwing
Co-authored-by: AGiorgetti <246067+AGiorgetti@users.noreply.github.com>
1 parent 021dba1 commit 31fa72c

3 files changed

Lines changed: 136 additions & 6 deletions

File tree

Changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
### Bug Fixes
66

7+
- `IServiceCollection` lifetime check methods (`IsTransientServiceRegistered`, `IsScopedServiceRegistered`, `IsSingletonServiceRegistered`, and their keyed variants) now return `false` instead of throwing `InvalidOperationException` when the service is not registered.
78
- Fixed `ResolutionContext` stack corruption in `PatchForResolutionContextTracking` when a factory delegate throws an exception. Push/Pop calls are now wrapped in `try/finally` for all 4 registration paths (non-keyed/keyed × factory/type).
89
- Fixed bidirectional `IsAssignableFrom` check in `GetServiceDescriptors` method that incorrectly returned unrelated base-type registrations [#19](https://github.com/PrimordialCode/Mammoth.Extensions.DependencyInjection/issues/19).
910
- The method now uses unidirectional matching: `serviceType == serviceDescriptor.ServiceType || serviceType.IsAssignableFrom(serviceDescriptor.ServiceType)`.
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
using Microsoft.Extensions.DependencyInjection;
2+
using Mammoth.Cqrs.Infrastructure.Tests.Infrastructure;
3+
4+
namespace Mammoth.Extensions.DependencyInjection.Tests
5+
{
6+
[TestClass]
7+
public class ServiceCollectionExtensionsRegistrationTests
8+
{
9+
[TestMethod]
10+
public void IsTransientServiceRegistered_Returns_False_When_Service_Not_Registered()
11+
{
12+
var serviceCollection = new ServiceCollection();
13+
14+
Assert.IsFalse(serviceCollection.IsTransientServiceRegistered<TestService>());
15+
Assert.IsFalse(serviceCollection.IsTransientServiceRegistered(typeof(TestService)));
16+
}
17+
18+
[TestMethod]
19+
public void IsScopedServiceRegistered_Returns_False_When_Service_Not_Registered()
20+
{
21+
var serviceCollection = new ServiceCollection();
22+
23+
Assert.IsFalse(serviceCollection.IsScopedServiceRegistered<TestService>());
24+
Assert.IsFalse(serviceCollection.IsScopedServiceRegistered(typeof(TestService)));
25+
}
26+
27+
[TestMethod]
28+
public void IsSingletonServiceRegistered_Returns_False_When_Service_Not_Registered()
29+
{
30+
var serviceCollection = new ServiceCollection();
31+
32+
Assert.IsFalse(serviceCollection.IsSingletonServiceRegistered<TestService>());
33+
Assert.IsFalse(serviceCollection.IsSingletonServiceRegistered(typeof(TestService)));
34+
}
35+
36+
[TestMethod]
37+
public void IsKeyedSingletonServiceRegistered_Returns_False_When_Service_Not_Registered()
38+
{
39+
var serviceCollection = new ServiceCollection();
40+
41+
Assert.IsFalse(serviceCollection.IsKeyedSingletonServiceRegistered<TestService>("key"));
42+
Assert.IsFalse(serviceCollection.IsKeyedSingletonServiceRegistered(typeof(TestService), "key"));
43+
}
44+
45+
[TestMethod]
46+
public void IsKeyedScopedServiceRegistered_Returns_False_When_Service_Not_Registered()
47+
{
48+
var serviceCollection = new ServiceCollection();
49+
50+
Assert.IsFalse(serviceCollection.IsKeyedScopedServiceRegistered<TestService>("key"));
51+
Assert.IsFalse(serviceCollection.IsKeyedScopedServiceRegistered(typeof(TestService), "key"));
52+
}
53+
54+
[TestMethod]
55+
public void IsKeyedTransientServiceRegistered_Returns_False_When_Service_Not_Registered()
56+
{
57+
var serviceCollection = new ServiceCollection();
58+
59+
Assert.IsFalse(serviceCollection.IsKeyedTransientServiceRegistered<TestService>("key"));
60+
Assert.IsFalse(serviceCollection.IsKeyedTransientServiceRegistered(typeof(TestService), "key"));
61+
}
62+
63+
[TestMethod]
64+
public void IsTransientServiceRegistered_Returns_True_When_Registered_As_Transient()
65+
{
66+
var serviceCollection = new ServiceCollection();
67+
serviceCollection.AddTransient<TestService>();
68+
69+
Assert.IsTrue(serviceCollection.IsTransientServiceRegistered<TestService>());
70+
Assert.IsFalse(serviceCollection.IsScopedServiceRegistered<TestService>());
71+
Assert.IsFalse(serviceCollection.IsSingletonServiceRegistered<TestService>());
72+
}
73+
74+
[TestMethod]
75+
public void IsScopedServiceRegistered_Returns_True_When_Registered_As_Scoped()
76+
{
77+
var serviceCollection = new ServiceCollection();
78+
serviceCollection.AddScoped<TestService>();
79+
80+
Assert.IsFalse(serviceCollection.IsTransientServiceRegistered<TestService>());
81+
Assert.IsTrue(serviceCollection.IsScopedServiceRegistered<TestService>());
82+
Assert.IsFalse(serviceCollection.IsSingletonServiceRegistered<TestService>());
83+
}
84+
85+
[TestMethod]
86+
public void IsSingletonServiceRegistered_Returns_True_When_Registered_As_Singleton()
87+
{
88+
var serviceCollection = new ServiceCollection();
89+
serviceCollection.AddSingleton<TestService>();
90+
91+
Assert.IsFalse(serviceCollection.IsTransientServiceRegistered<TestService>());
92+
Assert.IsFalse(serviceCollection.IsScopedServiceRegistered<TestService>());
93+
Assert.IsTrue(serviceCollection.IsSingletonServiceRegistered<TestService>());
94+
}
95+
96+
[TestMethod]
97+
public void IsKeyedTransientServiceRegistered_Returns_True_When_Registered_As_Keyed_Transient()
98+
{
99+
var serviceCollection = new ServiceCollection();
100+
serviceCollection.AddKeyedTransient<TestService>("key");
101+
102+
Assert.IsTrue(serviceCollection.IsKeyedTransientServiceRegistered<TestService>("key"));
103+
Assert.IsFalse(serviceCollection.IsKeyedScopedServiceRegistered<TestService>("key"));
104+
Assert.IsFalse(serviceCollection.IsKeyedSingletonServiceRegistered<TestService>("key"));
105+
}
106+
107+
[TestMethod]
108+
public void IsKeyedScopedServiceRegistered_Returns_True_When_Registered_As_Keyed_Scoped()
109+
{
110+
var serviceCollection = new ServiceCollection();
111+
serviceCollection.AddKeyedScoped<TestService>("key");
112+
113+
Assert.IsFalse(serviceCollection.IsKeyedTransientServiceRegistered<TestService>("key"));
114+
Assert.IsTrue(serviceCollection.IsKeyedScopedServiceRegistered<TestService>("key"));
115+
Assert.IsFalse(serviceCollection.IsKeyedSingletonServiceRegistered<TestService>("key"));
116+
}
117+
118+
[TestMethod]
119+
public void IsKeyedSingletonServiceRegistered_Returns_True_When_Registered_As_Keyed_Singleton()
120+
{
121+
var serviceCollection = new ServiceCollection();
122+
serviceCollection.AddKeyedSingleton<TestService>("key");
123+
124+
Assert.IsFalse(serviceCollection.IsKeyedTransientServiceRegistered<TestService>("key"));
125+
Assert.IsFalse(serviceCollection.IsKeyedScopedServiceRegistered<TestService>("key"));
126+
Assert.IsTrue(serviceCollection.IsKeyedSingletonServiceRegistered<TestService>("key"));
127+
}
128+
}
129+
}

src/Mammoth.Extensions.DependencyInjection/ServiceCollectionExtensions.Registration.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ public static bool IsTransientServiceRegistered(this IServiceCollection services
8484
}
8585

8686
var descriptors = services.GetServiceDescriptors(serviceType, isKeyedService: false);
87-
return descriptors.Last().Lifetime == ServiceLifetime.Transient;
87+
return descriptors.Length > 0 && descriptors[descriptors.Length - 1].Lifetime == ServiceLifetime.Transient;
8888
}
8989

9090
/// <summary>
@@ -112,7 +112,7 @@ public static bool IsScopedServiceRegistered(this IServiceCollection services, T
112112
}
113113

114114
var descriptors = services.GetServiceDescriptors(serviceType, isKeyedService: false);
115-
return descriptors.Last().Lifetime == ServiceLifetime.Scoped;
115+
return descriptors.Length > 0 && descriptors[descriptors.Length - 1].Lifetime == ServiceLifetime.Scoped;
116116
}
117117

118118
/// <summary>
@@ -140,7 +140,7 @@ public static bool IsSingletonServiceRegistered(this IServiceCollection services
140140
}
141141

142142
var descriptors = services.GetServiceDescriptors(serviceType, isKeyedService: false);
143-
return descriptors.Last().Lifetime == ServiceLifetime.Singleton;
143+
return descriptors.Length > 0 && descriptors[descriptors.Length - 1].Lifetime == ServiceLifetime.Singleton;
144144
}
145145

146146
/// <summary>
@@ -176,7 +176,7 @@ public static bool IsKeyedSingletonServiceRegistered(this IServiceCollection ser
176176
var descriptors = services.GetServiceDescriptors(serviceType, isKeyedService: true)
177177
.Where(d => d.ServiceKey == serviceKey)
178178
.ToArray();
179-
return descriptors.Last().Lifetime == ServiceLifetime.Singleton;
179+
return descriptors.Length > 0 && descriptors[descriptors.Length - 1].Lifetime == ServiceLifetime.Singleton;
180180
}
181181

182182
/// <summary>
@@ -212,7 +212,7 @@ public static bool IsKeyedScopedServiceRegistered(this IServiceCollection servic
212212
var descriptors = services.GetServiceDescriptors(serviceType, isKeyedService: true)
213213
.Where(d => d.ServiceKey == serviceKey)
214214
.ToArray();
215-
return descriptors.Last().Lifetime == ServiceLifetime.Scoped;
215+
return descriptors.Length > 0 && descriptors[descriptors.Length - 1].Lifetime == ServiceLifetime.Scoped;
216216
}
217217

218218
/// <summary>
@@ -248,7 +248,7 @@ public static bool IsKeyedTransientServiceRegistered(this IServiceCollection ser
248248
var descriptors = services.GetServiceDescriptors(serviceType, isKeyedService: true)
249249
.Where(d => d.ServiceKey == serviceKey)
250250
.ToArray();
251-
return descriptors.Last().Lifetime == ServiceLifetime.Transient;
251+
return descriptors.Length > 0 && descriptors[descriptors.Length - 1].Lifetime == ServiceLifetime.Transient;
252252
}
253253

254254
/// <summary>

0 commit comments

Comments
 (0)