diff --git a/examples/BlazorServerExample/Program.cs b/examples/BlazorServerExample/Program.cs index 2cc39e8..e2bc813 100644 --- a/examples/BlazorServerExample/Program.cs +++ b/examples/BlazorServerExample/Program.cs @@ -8,7 +8,7 @@ builder.Services.AddSingleton(); // Add EasyScrutor - Automatically scans and registers services -builder.Services.AddAdvancedDependencyInjection(); +builder.Services.AddEasyScrutor(); var app = builder.Build(); diff --git a/examples/ConsoleHostExample/Program.cs b/examples/ConsoleHostExample/Program.cs index 5bc8aff..74110f6 100644 --- a/examples/ConsoleHostExample/Program.cs +++ b/examples/ConsoleHostExample/Program.cs @@ -4,7 +4,7 @@ // Add EasyScrutor - Automatically scans and registers all services // This will find and register IDataProcessor and IMetricsCollector without manual configuration -builder.Services.AddAdvancedDependencyInjection(); +builder.Services.AddEasyScrutor(); builder.Services.AddHostedService(); diff --git a/examples/MvcExample/Program.cs b/examples/MvcExample/Program.cs index 1996a6f..1500519 100644 --- a/examples/MvcExample/Program.cs +++ b/examples/MvcExample/Program.cs @@ -4,7 +4,7 @@ builder.Services.AddControllersWithViews(); // Add EasyScrutor - Automatically scans and registers services -builder.Services.AddAdvancedDependencyInjection(); +builder.Services.AddEasyScrutor(); var app = builder.Build(); diff --git a/examples/WebApiExample/Program.cs b/examples/WebApiExample/Program.cs index 8e6f8ec..bc2d6e5 100644 --- a/examples/WebApiExample/Program.cs +++ b/examples/WebApiExample/Program.cs @@ -7,7 +7,7 @@ builder.Services.AddOpenApi(); // Add EasyScrutor - Automatically scans and registers services based on lifetime interfaces -builder.Services.AddAdvancedDependencyInjection(); +builder.Services.AddEasyScrutor(); var app = builder.Build(); diff --git a/src/EasyScrutor/ServiceCollectionExtensions.cs b/src/EasyScrutor/ServiceCollectionExtensions.cs index 69e8dcc..ea8a899 100644 --- a/src/EasyScrutor/ServiceCollectionExtensions.cs +++ b/src/EasyScrutor/ServiceCollectionExtensions.cs @@ -15,7 +15,7 @@ public static class ServiceCollectionExtensions { /// /// The service collection to add services to. /// The service collection for chaining. - public static IServiceCollection AddAdvancedDependencyInjection(this IServiceCollection services) { + public static IServiceCollection AddEasyScrutor(this IServiceCollection services) { services.Scan(scan => scan .FromDependencyContext(DependencyModel.DependencyContext.Default) .AddClassesFromInterfaces()); @@ -30,7 +30,7 @@ public static IServiceCollection AddAdvancedDependencyInjection(this IServiceCol /// The service collection to add services to. /// A predicate to filter which assemblies to scan. /// The service collection for chaining. - public static IServiceCollection AddAdvancedDependencyInjection(this IServiceCollection services, Func predicate) { + public static IServiceCollection AddEasyScrutor(this IServiceCollection services, Func predicate) { services.Scan(scan => scan .FromDependencyContext(DependencyModel.DependencyContext.Default, predicate) .AddClassesFromInterfaces()); @@ -38,6 +38,38 @@ public static IServiceCollection AddAdvancedDependencyInjection(this IServiceCol return services; } + /// + /// Scans and registers services from assemblies whose names start with the specified prefix. + /// Services are registered based on their implemented lifetime interfaces (ISingletonLifetime, ITransientLifetime, IScopedLifetime). + /// + /// The service collection to add services to. + /// The prefix that assembly names must start with. + /// The service collection for chaining. + public static IServiceCollection AddEasyScrutorForAssembliesStartingWith(this IServiceCollection services, string prefix) { + services.Scan(scan => scan + .FromDependencyContext(DependencyModel.DependencyContext.Default, assembly => + assembly.FullName != null && assembly.FullName.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) + .AddClassesFromInterfaces()); + + return services; + } + + /// + /// Scans and registers services from assemblies whose names contain the specified text. + /// Services are registered based on their implemented lifetime interfaces (ISingletonLifetime, ITransientLifetime, IScopedLifetime). + /// + /// The service collection to add services to. + /// The text that assembly names must contain. + /// The service collection for chaining. + public static IServiceCollection AddEasyScrutorForAssembliesContaining(this IServiceCollection services, string text) { + services.Scan(scan => scan + .FromDependencyContext(DependencyModel.DependencyContext.Default, assembly => + assembly.FullName != null && assembly.FullName.Contains(text, StringComparison.OrdinalIgnoreCase)) + .AddClassesFromInterfaces()); + + return services; + } + /// /// Configures service registration based on lifetime marker interfaces. /// Scans for classes implementing ISingletonLifetime, ITransientLifetime, IScopedLifetime, and their self-registration variants. diff --git a/tests/EasyScrutor.Tests/AdvancedDependencyInjectionTests.cs b/tests/EasyScrutor.Tests/AdvancedDependencyInjectionTests.cs index 42d93ea..72f272d 100644 --- a/tests/EasyScrutor.Tests/AdvancedDependencyInjectionTests.cs +++ b/tests/EasyScrutor.Tests/AdvancedDependencyInjectionTests.cs @@ -6,12 +6,12 @@ namespace EasyScrutor.Tests; [TestFixture] public class AdvancedDependencyInjectionTests { [Test] - public void AddAdvancedDependencyInjection_WithoutPredicate_ShouldRegisterAllServices() { + public void AddEasyScrutor_WithoutPredicate_ShouldRegisterAllServices() { // Arrange var services = new ServiceCollection(); // Act - services.AddAdvancedDependencyInjection(); + services.AddEasyScrutor(); var serviceProvider = services.BuildServiceProvider(); // Assert @@ -24,13 +24,13 @@ public void AddAdvancedDependencyInjection_WithoutPredicate_ShouldRegisterAllSer } [Test] - public void AddAdvancedDependencyInjection_WithPredicate_ShouldOnlyRegisterMatchingAssemblies() { + public void AddEasyScrutor_WithPredicate_ShouldOnlyRegisterMatchingAssemblies() { // Arrange var services = new ServiceCollection(); var testAssemblyName = Assembly.GetExecutingAssembly().GetName().Name; // Act - services.AddAdvancedDependencyInjection(assembly => + services.AddEasyScrutor(assembly => assembly.FullName != null && assembly.FullName.Contains(testAssemblyName!)); var serviceProvider = services.BuildServiceProvider(); @@ -41,12 +41,12 @@ public void AddAdvancedDependencyInjection_WithPredicate_ShouldOnlyRegisterMatch } [Test] - public void AddAdvancedDependencyInjection_WithExcludingPredicate_ShouldNotRegisterFilteredAssemblies() { + public void AddEasyScrutor_WithExcludingPredicate_ShouldNotRegisterFilteredAssemblies() { // Arrange var services = new ServiceCollection(); // Act - Exclude assemblies containing "NonExistent" - services.AddAdvancedDependencyInjection(assembly => + services.AddEasyScrutor(assembly => assembly.FullName != null && !assembly.FullName.Contains("NonExistent")); var serviceProvider = services.BuildServiceProvider(); @@ -55,13 +55,13 @@ public void AddAdvancedDependencyInjection_WithExcludingPredicate_ShouldNotRegis } [Test] - public void AddAdvancedDependencyInjection_CalledMultipleTimes_ShouldSkipDuplicates() { + public void AddEasyScrutor_CalledMultipleTimes_ShouldSkipDuplicates() { // Arrange var services = new ServiceCollection(); // Act - services.AddAdvancedDependencyInjection(); - services.AddAdvancedDependencyInjection(); + services.AddEasyScrutor(); + services.AddEasyScrutor(); // Assert - Should only have one registration due to Skip strategy var singletonServices = services.Where(s => s.ServiceType == typeof(ISingletonService)).ToList(); @@ -74,7 +74,7 @@ public void ServiceRegistration_ShouldRespectRegistrationStrategy() { var services = new ServiceCollection(); // Act - services.AddAdvancedDependencyInjection(); + services.AddEasyScrutor(); // Try to add a manual registration - it should be skipped due to RegistrationStrategy.Skip services.AddSingleton(); @@ -89,7 +89,7 @@ public void ServiceRegistration_ShouldRespectRegistrationStrategy() { public void ComplexService_WithDependencies_ShouldResolveCorrectly() { // Arrange var services = new ServiceCollection(); - services.AddAdvancedDependencyInjection(); + services.AddEasyScrutor(); var serviceProvider = services.BuildServiceProvider(); // Act @@ -110,7 +110,7 @@ public void ServiceCollection_ShouldReturnItself_ForChaining() { var services = new ServiceCollection(); // Act - var result = services.AddAdvancedDependencyInjection(); + var result = services.AddEasyScrutor(); // Assert Assert.That(result, Is.SameAs(services), "Should return the same ServiceCollection for method chaining"); @@ -120,7 +120,7 @@ public void ServiceCollection_ShouldReturnItself_ForChaining() { public void AllLifetimeInterfaces_ShouldBeRegistered() { // Arrange var services = new ServiceCollection(); - services.AddAdvancedDependencyInjection(); + services.AddEasyScrutor(); var serviceProvider = services.BuildServiceProvider(); // Act & Assert - Verify all 6 lifetime interfaces are working @@ -138,7 +138,7 @@ public void AllLifetimeInterfaces_ShouldBeRegistered() { public void MultipleImplementations_ShouldRegisterFirst() { // Arrange var services = new ServiceCollection(); - services.AddAdvancedDependencyInjection(); + services.AddEasyScrutor(); var serviceProvider = services.BuildServiceProvider(); // Act @@ -154,7 +154,7 @@ public void MultipleImplementations_ShouldRegisterFirst() { public void AbstractBaseClass_ShouldNotBeRegistered() { // Arrange var services = new ServiceCollection(); - services.AddAdvancedDependencyInjection(); + services.AddEasyScrutor(); // Act var abstractRegistrations = services.Where(s => s.ImplementationType == typeof(BaseService)).ToList(); @@ -167,7 +167,7 @@ public void AbstractBaseClass_ShouldNotBeRegistered() { public void ConcreteClassFromAbstract_ShouldBeRegistered() { // Arrange var services = new ServiceCollection(); - services.AddAdvancedDependencyInjection(); + services.AddEasyScrutor(); var serviceProvider = services.BuildServiceProvider(); // Act diff --git a/tests/EasyScrutor.Tests/AssemblyFilterTests.cs b/tests/EasyScrutor.Tests/AssemblyFilterTests.cs new file mode 100644 index 0000000..490e02f --- /dev/null +++ b/tests/EasyScrutor.Tests/AssemblyFilterTests.cs @@ -0,0 +1,240 @@ +using EasyScrutor.Tests.TestServices; +using System.Reflection; + +namespace EasyScrutor.Tests; + +/// +/// Tests for assembly filtering methods like AddEasyScrutorForAssembliesStartingWith and AddEasyScrutorForAssembliesContaining. +/// +[TestFixture] +public class AssemblyFilterTests { + [Test] + public void AddEasyScrutorForAssembliesStartingWith_MatchingPrefix_ShouldRegisterServices() { + // Arrange + var services = new ServiceCollection(); + var testAssemblyName = Assembly.GetExecutingAssembly().GetName().Name; + var prefix = testAssemblyName!.Substring(0, 10); // Get first 10 characters as prefix + + // Act + services.AddEasyScrutorForAssembliesStartingWith(prefix); + var serviceProvider = services.BuildServiceProvider(); + + // Assert + Assert.That(serviceProvider.GetService(), Is.Not.Null); + Assert.That(serviceProvider.GetService(), Is.Not.Null); + Assert.That(serviceProvider.GetService(), Is.Not.Null); + } + + [Test] + public void AddEasyScrutorForAssembliesStartingWith_NonMatchingPrefix_ShouldNotRegisterServices() { + // Arrange + var services = new ServiceCollection(); + + // Act + services.AddEasyScrutorForAssembliesStartingWith("NonExistentPrefix"); + var serviceProvider = services.BuildServiceProvider(); + + // Assert + Assert.That(serviceProvider.GetService(), Is.Null); + Assert.That(serviceProvider.GetService(), Is.Null); + Assert.That(serviceProvider.GetService(), Is.Null); + } + + [Test] + public void AddEasyScrutorForAssembliesStartingWith_CaseInsensitive_ShouldRegisterServices() { + // Arrange + var services = new ServiceCollection(); + var testAssemblyName = Assembly.GetExecutingAssembly().GetName().Name; + var prefix = testAssemblyName!.Substring(0, 10).ToLower(); // Lowercase prefix + + // Act + services.AddEasyScrutorForAssembliesStartingWith(prefix); + var serviceProvider = services.BuildServiceProvider(); + + // Assert + Assert.That(serviceProvider.GetService(), Is.Not.Null, "Should be case-insensitive"); + } + + [Test] + public void AddEasyScrutorForAssembliesStartingWith_ShouldReturnServiceCollection_ForChaining() { + // Arrange + var services = new ServiceCollection(); + + // Act + var result = services.AddEasyScrutorForAssembliesStartingWith("Test"); + + // Assert + Assert.That(result, Is.SameAs(services), "Should return the same ServiceCollection for method chaining"); + } + + [Test] + public void AddEasyScrutorForAssembliesContaining_MatchingText_ShouldRegisterServices() { + // Arrange + var services = new ServiceCollection(); + var containingText = "Scrutor"; // Should be part of the assembly name + + // Act + services.AddEasyScrutorForAssembliesContaining(containingText); + var serviceProvider = services.BuildServiceProvider(); + + // Assert + Assert.That(serviceProvider.GetService(), Is.Not.Null); + Assert.That(serviceProvider.GetService(), Is.Not.Null); + Assert.That(serviceProvider.GetService(), Is.Not.Null); + } + + [Test] + public void AddEasyScrutorForAssembliesContaining_NonMatchingText_ShouldNotRegisterServices() { + // Arrange + var services = new ServiceCollection(); + + // Act + services.AddEasyScrutorForAssembliesContaining("NonExistentText"); + var serviceProvider = services.BuildServiceProvider(); + + // Assert + Assert.That(serviceProvider.GetService(), Is.Null); + Assert.That(serviceProvider.GetService(), Is.Null); + Assert.That(serviceProvider.GetService(), Is.Null); + } + + [Test] + public void AddEasyScrutorForAssembliesContaining_CaseInsensitive_ShouldRegisterServices() { + // Arrange + var services = new ServiceCollection(); + var containingText = "SCRUTOR"; // Uppercase + + // Act + services.AddEasyScrutorForAssembliesContaining(containingText); + var serviceProvider = services.BuildServiceProvider(); + + // Assert + Assert.That(serviceProvider.GetService(), Is.Not.Null, "Should be case-insensitive"); + } + + [Test] + public void AddEasyScrutorForAssembliesContaining_ShouldReturnServiceCollection_ForChaining() { + // Arrange + var services = new ServiceCollection(); + + // Act + var result = services.AddEasyScrutorForAssembliesContaining("Test"); + + // Assert + Assert.That(result, Is.SameAs(services), "Should return the same ServiceCollection for method chaining"); + } + + [Test] + public void AddEasyScrutorForAssembliesContaining_PartialMatch_ShouldRegisterServices() { + // Arrange + var services = new ServiceCollection(); + var testAssemblyName = Assembly.GetExecutingAssembly().GetName().Name; + // Take middle part of assembly name + var partialText = testAssemblyName!.Substring(5, 5); + + // Act + services.AddEasyScrutorForAssembliesContaining(partialText); + var serviceProvider = services.BuildServiceProvider(); + + // Assert + Assert.That(serviceProvider.GetService(), Is.Not.Null, "Should match partial text"); + } + + [Test] + public void AddEasyScrutorForAssembliesStartingWith_CalledMultipleTimes_ShouldSkipDuplicates() { + // Arrange + var services = new ServiceCollection(); + var testAssemblyName = Assembly.GetExecutingAssembly().GetName().Name; + var prefix = testAssemblyName!.Substring(0, 10); + + // Act + services.AddEasyScrutorForAssembliesStartingWith(prefix); + services.AddEasyScrutorForAssembliesStartingWith(prefix); + + // Assert - Should only have one registration due to Skip strategy + var singletonServices = services.Where(s => s.ServiceType == typeof(ISingletonService)).ToList(); + Assert.That(singletonServices.Count, Is.EqualTo(1), "Should not register duplicate services"); + } + + [Test] + public void AddEasyScrutorForAssembliesContaining_CalledMultipleTimes_ShouldSkipDuplicates() { + // Arrange + var services = new ServiceCollection(); + + // Act + services.AddEasyScrutorForAssembliesContaining("Scrutor"); + services.AddEasyScrutorForAssembliesContaining("Scrutor"); + + // Assert - Should only have one registration due to Skip strategy + var singletonServices = services.Where(s => s.ServiceType == typeof(ISingletonService)).ToList(); + Assert.That(singletonServices.Count, Is.EqualTo(1), "Should not register duplicate services"); + } + + [Test] + public void AddEasyScrutorForAssembliesStartingWith_AllLifetimeInterfaces_ShouldBeRegistered() { + // Arrange + var services = new ServiceCollection(); + var testAssemblyName = Assembly.GetExecutingAssembly().GetName().Name; + var prefix = testAssemblyName!.Substring(0, 10); + + // Act + services.AddEasyScrutorForAssembliesStartingWith(prefix); + var serviceProvider = services.BuildServiceProvider(); + + // Assert - Verify all 6 lifetime interfaces are working + using var scope = serviceProvider.CreateScope(); + + Assert.That(scope.ServiceProvider.GetService(), Is.Not.Null, "ISingletonLifetime should work"); + Assert.That(scope.ServiceProvider.GetService(), Is.Not.Null, "ISelfSingletonLifetime should work"); + Assert.That(scope.ServiceProvider.GetService(), Is.Not.Null, "ITransientLifetime should work"); + Assert.That(scope.ServiceProvider.GetService(), Is.Not.Null, "ISelfTransientLifetime should work"); + Assert.That(scope.ServiceProvider.GetService(), Is.Not.Null, "IScopedLifetime should work"); + Assert.That(scope.ServiceProvider.GetService(), Is.Not.Null, "ISelfScopedLifetime should work"); + } + + [Test] + public void AddEasyScrutorForAssembliesContaining_AllLifetimeInterfaces_ShouldBeRegistered() { + // Arrange + var services = new ServiceCollection(); + + // Act + services.AddEasyScrutorForAssembliesContaining("Scrutor"); + var serviceProvider = services.BuildServiceProvider(); + + // Assert - Verify all 6 lifetime interfaces are working + using var scope = serviceProvider.CreateScope(); + + Assert.That(scope.ServiceProvider.GetService(), Is.Not.Null, "ISingletonLifetime should work"); + Assert.That(scope.ServiceProvider.GetService(), Is.Not.Null, "ISelfSingletonLifetime should work"); + Assert.That(scope.ServiceProvider.GetService(), Is.Not.Null, "ITransientLifetime should work"); + Assert.That(scope.ServiceProvider.GetService(), Is.Not.Null, "ISelfTransientLifetime should work"); + Assert.That(scope.ServiceProvider.GetService(), Is.Not.Null, "IScopedLifetime should work"); + Assert.That(scope.ServiceProvider.GetService(), Is.Not.Null, "ISelfScopedLifetime should work"); + } + + [Test] + public void AddEasyScrutorForAssembliesStartingWith_EmptyPrefix_ShouldMatchAllAssemblies() { + // Arrange + var services = new ServiceCollection(); + + // Act + services.AddEasyScrutorForAssembliesStartingWith(""); + var serviceProvider = services.BuildServiceProvider(); + + // Assert - Empty prefix matches everything + Assert.That(serviceProvider.GetService(), Is.Not.Null); + } + + [Test] + public void AddEasyScrutorForAssembliesContaining_EmptyText_ShouldMatchAllAssemblies() { + // Arrange + var services = new ServiceCollection(); + + // Act + services.AddEasyScrutorForAssembliesContaining(""); + var serviceProvider = services.BuildServiceProvider(); + + // Assert - Empty text matches everything + Assert.That(serviceProvider.GetService(), Is.Not.Null); + } +} diff --git a/tests/EasyScrutor.Tests/ScopedLifetimeTests.cs b/tests/EasyScrutor.Tests/ScopedLifetimeTests.cs index 3b93610..2a49eb3 100644 --- a/tests/EasyScrutor.Tests/ScopedLifetimeTests.cs +++ b/tests/EasyScrutor.Tests/ScopedLifetimeTests.cs @@ -9,7 +9,7 @@ public class ScopedLifetimeTests { [SetUp] public void Setup() { var services = new ServiceCollection(); - services.AddAdvancedDependencyInjection(); + services.AddEasyScrutor(); _serviceProvider = services.BuildServiceProvider(); } diff --git a/tests/EasyScrutor.Tests/ServiceLifecycleIntegrationTests.cs b/tests/EasyScrutor.Tests/ServiceLifecycleIntegrationTests.cs index ad67e62..386ce75 100644 --- a/tests/EasyScrutor.Tests/ServiceLifecycleIntegrationTests.cs +++ b/tests/EasyScrutor.Tests/ServiceLifecycleIntegrationTests.cs @@ -8,7 +8,7 @@ public class ServiceLifecycleIntegrationTests { public void MixedLifetimes_ShouldWorkTogetherCorrectly() { // Arrange var services = new ServiceCollection(); - services.AddAdvancedDependencyInjection(); + services.AddEasyScrutor(); var serviceProvider = services.BuildServiceProvider(); // Act @@ -60,7 +60,7 @@ public void MixedLifetimes_ShouldWorkTogetherCorrectly() { public void ComplexService_ShouldReceiveCorrectDependencies() { // Arrange var services = new ServiceCollection(); - services.AddAdvancedDependencyInjection(); + services.AddEasyScrutor(); var serviceProvider = services.BuildServiceProvider(); // Act @@ -95,7 +95,7 @@ public void ComplexService_ShouldReceiveCorrectDependencies() { public void SelfRegisteredServices_ShouldOnlyBeAvailableAsSelf() { // Arrange var services = new ServiceCollection(); - services.AddAdvancedDependencyInjection(); + services.AddEasyScrutor(); var serviceProvider = services.BuildServiceProvider(); // Act @@ -113,7 +113,7 @@ public void SelfRegisteredServices_ShouldOnlyBeAvailableAsSelf() { public void InterfaceRegisteredServices_ShouldBeAvailableViaInterface() { // Arrange var services = new ServiceCollection(); - services.AddAdvancedDependencyInjection(); + services.AddEasyScrutor(); var serviceProvider = services.BuildServiceProvider(); // Act @@ -131,7 +131,7 @@ public void InterfaceRegisteredServices_ShouldBeAvailableViaInterface() { public void InterfaceRegisteredServices_ShouldNotBeAvailableAsConcreteType() { // Arrange var services = new ServiceCollection(); - services.AddAdvancedDependencyInjection(); + services.AddEasyScrutor(); var serviceProvider = services.BuildServiceProvider(); // Act @@ -149,7 +149,7 @@ public void InterfaceRegisteredServices_ShouldNotBeAvailableAsConcreteType() { public void ServiceProvider_Dispose_ShouldDisposeDisposableServices() { // Arrange var services = new ServiceCollection(); - services.AddAdvancedDependencyInjection(); + services.AddEasyScrutor(); using (var serviceProvider = services.BuildServiceProvider()) { // Act var singleton = serviceProvider.GetService(); diff --git a/tests/EasyScrutor.Tests/SingletonLifetimeTests.cs b/tests/EasyScrutor.Tests/SingletonLifetimeTests.cs index c14bff9..a759d89 100644 --- a/tests/EasyScrutor.Tests/SingletonLifetimeTests.cs +++ b/tests/EasyScrutor.Tests/SingletonLifetimeTests.cs @@ -9,7 +9,7 @@ public class SingletonLifetimeTests { [SetUp] public void Setup() { var services = new ServiceCollection(); - services.AddAdvancedDependencyInjection(); + services.AddEasyScrutor(); _serviceProvider = services.BuildServiceProvider(); } diff --git a/tests/EasyScrutor.Tests/TransientLifetimeTests.cs b/tests/EasyScrutor.Tests/TransientLifetimeTests.cs index 95074b4..68a0dd0 100644 --- a/tests/EasyScrutor.Tests/TransientLifetimeTests.cs +++ b/tests/EasyScrutor.Tests/TransientLifetimeTests.cs @@ -9,7 +9,7 @@ public class TransientLifetimeTests { [SetUp] public void Setup() { var services = new ServiceCollection(); - services.AddAdvancedDependencyInjection(); + services.AddEasyScrutor(); _serviceProvider = services.BuildServiceProvider(); }