diff --git a/src/Scrutor/RegistrationStrategy.cs b/src/Scrutor/RegistrationStrategy.cs
index 4894384..adff036 100644
--- a/src/Scrutor/RegistrationStrategy.cs
+++ b/src/Scrutor/RegistrationStrategy.cs
@@ -1,14 +1,27 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
+using System.Linq;
namespace Scrutor;
public abstract class RegistrationStrategy
{
///
- /// Skips registrations for services that already exists.
+ /// Skips registrations for services that already exist using .
///
- public static readonly RegistrationStrategy Skip = new SkipRegistrationStrategy();
+ public static RegistrationStrategy Skip()
+ {
+ return new SkipRegistrationStrategy(SkipBehavior.Default);
+ }
+
+ ///
+ /// Skips registrations for services that already exist based on the specified .
+ ///
+ /// The behavior to use when replacing services.
+ public static RegistrationStrategy Skip(SkipBehavior behavior)
+ {
+ return new SkipRegistrationStrategy(behavior);
+ }
///
/// Appends a new registration for existing services.
@@ -38,7 +51,7 @@ public static RegistrationStrategy Replace(ReplacementBehavior behavior)
}
///
- /// Applies the the to the .
+ /// Applies the selected for the to the .
///
/// The service collection.
/// The descriptor to apply.
@@ -46,7 +59,31 @@ public static RegistrationStrategy Replace(ReplacementBehavior behavior)
private sealed class SkipRegistrationStrategy : RegistrationStrategy
{
- public override void Apply(IServiceCollection services, ServiceDescriptor descriptor) => services.TryAdd(descriptor);
+ public SkipRegistrationStrategy(SkipBehavior behavior)
+ {
+ Behavior = behavior;
+ }
+
+ private SkipBehavior Behavior { get; }
+
+ public override void Apply(IServiceCollection services, ServiceDescriptor descriptor)
+ {
+ if (Behavior is SkipBehavior.Default or SkipBehavior.ServiceType)
+ {
+ services.TryAdd(descriptor);
+ }
+ else if (Behavior is SkipBehavior.ImplementationType)
+ {
+ if (!services.Any((ServiceDescriptor d) => d.ImplementationType == descriptor.ImplementationType))
+ {
+ services.Add(descriptor);
+ }
+ }
+ else
+ {
+ services.TryAddEnumerable(descriptor);
+ }
+ }
}
private sealed class AppendRegistrationStrategy : RegistrationStrategy
@@ -110,4 +147,4 @@ public override void Apply(IServiceCollection services, ServiceDescriptor descri
services.Add(descriptor);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Scrutor/ReplacementBehavior.cs b/src/Scrutor/ReplacementBehavior.cs
index 23aaff4..543110c 100644
--- a/src/Scrutor/ReplacementBehavior.cs
+++ b/src/Scrutor/ReplacementBehavior.cs
@@ -21,7 +21,7 @@ public enum ReplacementBehavior
ImplementationType = 2,
///
- /// Replace existing services by either service- or implementation type.
+ /// Replace existing services by either service or implementation type.
///
All = ServiceType | ImplementationType
-}
\ No newline at end of file
+}
diff --git a/src/Scrutor/SkipBehavior.cs b/src/Scrutor/SkipBehavior.cs
new file mode 100644
index 0000000..e2da658
--- /dev/null
+++ b/src/Scrutor/SkipBehavior.cs
@@ -0,0 +1,28 @@
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.DependencyInjection.Extensions;
+
+namespace Scrutor;
+
+public enum SkipBehavior
+{
+ ///
+ /// Skip registration if the service type has already been registered. Same as .
+ ///
+ Default = 0,
+
+ ///
+ /// Skip registration if the service type has already been registered (default). Same as .
+ ///
+ ServiceType = 1,
+
+ ///
+ /// Skip registration if the implementation type has already been registered.
+ ///
+ ImplementationType = 2,
+
+ ///
+ /// Skip registration if a descriptor with the same and implementation has already been registered.
+ ///
+ Exact = 3,
+}
+
diff --git a/test/Scrutor.Tests/ScanningTests.cs b/test/Scrutor.Tests/ScanningTests.cs
index 3627a6d..306b4cc 100644
--- a/test/Scrutor.Tests/ScanningTests.cs
+++ b/test/Scrutor.Tests/ScanningTests.cs
@@ -48,21 +48,86 @@ public void UsingRegistrationStrategy_None()
}
[Fact]
- public void UsingRegistrationStrategy_SkipIfExists()
+ public void UsingRegistrationStrategy_SkipDefault()
{
Collection.Scan(scan => scan
.FromAssemblyOf()
.AddClasses(classes => classes.AssignableTo())
+ .UsingRegistrationStrategy(RegistrationStrategy.Skip())
.AsImplementedInterfaces()
.WithTransientLifetime()
.AddClasses(classes => classes.AssignableTo())
- .UsingRegistrationStrategy(RegistrationStrategy.Skip)
+ .UsingRegistrationStrategy(RegistrationStrategy.Skip())
.AsImplementedInterfaces()
.WithSingletonLifetime());
var services = Collection.GetDescriptors();
- Assert.Equal(4, services.Count(x => x.ServiceType == typeof(ITransientService)));
+ Assert.Equal(1, services.Count(x => x.Lifetime == ServiceLifetime.Transient));
+ Assert.Equal(0, services.Count(x => x.Lifetime == ServiceLifetime.Singleton));
+ }
+
+ [Fact]
+ public void UsingRegistrationStrategy_SkipServiceTypes()
+ {
+ Collection.Scan(scan => scan
+ .FromAssemblyOf()
+ .AddClasses(classes => classes.AssignableTo())
+ .UsingRegistrationStrategy(RegistrationStrategy.Skip(SkipBehavior.ServiceType))
+ .AsImplementedInterfaces()
+ .WithTransientLifetime()
+ .AddClasses(classes => classes.AssignableTo())
+ .UsingRegistrationStrategy(RegistrationStrategy.Skip(SkipBehavior.ServiceType))
+ .AsImplementedInterfaces()
+ .WithSingletonLifetime());
+
+ var services = Collection.GetDescriptors();
+
+ Assert.Equal(1, services.Count(x => x.Lifetime == ServiceLifetime.Transient));
+ Assert.Equal(0, services.Count(x => x.Lifetime == ServiceLifetime.Singleton));
+ }
+
+ [Fact]
+ public void UsingRegistrationStrategy_SkipImplementationTypes()
+ {
+ Collection.Scan(scan => scan
+ .FromAssemblyOf()
+ .AddClasses(classes => classes.AssignableTo())
+ .UsingRegistrationStrategy(RegistrationStrategy.Skip(SkipBehavior.ImplementationType))
+ .AsImplementedInterfaces()
+ .WithTransientLifetime()
+ .AddClasses(classes => classes.AssignableTo())
+ .UsingRegistrationStrategy(RegistrationStrategy.Skip(SkipBehavior.ImplementationType))
+ .AsImplementedInterfaces()
+ .WithSingletonLifetime());
+
+
+ var services = Collection.GetDescriptors();
+
+ Assert.Equal(4, services.Count(x => x.Lifetime == ServiceLifetime.Transient));
+ Assert.Equal(0, services.Count(x => x.Lifetime == ServiceLifetime.Singleton));
+ Assert.Equal(0, services.Count(x => x.ServiceType == typeof(IOtherInheritance)));
+ }
+
+ [Fact]
+ public void UsingRegistrationStrategy_SkipExactTypes()
+ {
+ Collection.Scan(scan => scan
+ .FromAssemblyOf()
+ .AddClasses(classes => classes.AssignableTo())
+ .UsingRegistrationStrategy(RegistrationStrategy.Skip(SkipBehavior.Exact))
+ .AsImplementedInterfaces()
+ .WithTransientLifetime()
+ .AddClasses(classes => classes.AssignableTo())
+ .UsingRegistrationStrategy(RegistrationStrategy.Skip(SkipBehavior.Exact))
+ .AsImplementedInterfaces()
+ .WithSingletonLifetime());
+
+ var services = Collection.GetDescriptors();
+
+ Assert.Equal(4, services.Count(x => x.Lifetime == ServiceLifetime.Transient));
+ Assert.Equal(0, services.Count(x => x.Lifetime == ServiceLifetime.Singleton));
+ Assert.Equal(1, Collection.Count(x => x.ServiceType == typeof(IOtherInheritance)));
}
[Fact]
@@ -558,7 +623,7 @@ public interface IOtherInheritance { }
[ServiceDescriptor(typeof(IDuplicateInheritance))]
[ServiceDescriptor(typeof(IDuplicateInheritance))]
public class DuplicateInheritance : IDuplicateInheritance, IOtherInheritance { }
-
+
public interface IDefault1 { }
public interface IDefault2 { }
@@ -573,7 +638,7 @@ public class DefaultAttributes : IDefault3Level2, IDefault1, IDefault2 { }
[CompilerGenerated]
public class CompilerGenerated { }
- public class CombinedService2: IDefault1, IDefault2, IDefault3Level2 { }
+ public class CombinedService2 : IDefault1, IDefault2, IDefault3Level2 { }
}
namespace Scrutor.Tests.ChildNamespace