From be3930933750e26b144c5cfe925aebd4c283e014 Mon Sep 17 00:00:00 2001 From: Keith Dahlby Date: Thu, 5 Jun 2025 12:51:28 -0500 Subject: [PATCH 1/4] Bump to v3; depend on MEDI v6 --- src/Directory.Build.props | 2 +- .../StructureMap.Microsoft.DependencyInjection.csproj | 2 +- .../StructureMap.Microsoft.DependencyInjection.Tests.csproj | 4 ++-- .../StructureMapContainerTests.cs | 2 ++ 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 845107d..246990e 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -1,6 +1,6 @@ - 2.2.0 + 3.0.0 dustinsoftware netstandard2.0 $(NoWarn);CS1591 diff --git a/src/StructureMap.Microsoft.DependencyInjection/StructureMap.Microsoft.DependencyInjection.csproj b/src/StructureMap.Microsoft.DependencyInjection/StructureMap.Microsoft.DependencyInjection.csproj index 009319b..1ad9fc3 100644 --- a/src/StructureMap.Microsoft.DependencyInjection/StructureMap.Microsoft.DependencyInjection.csproj +++ b/src/StructureMap.Microsoft.DependencyInjection/StructureMap.Microsoft.DependencyInjection.csproj @@ -6,6 +6,6 @@ - + diff --git a/test/StructureMap.Microsoft.DependencyInjection.Tests/StructureMap.Microsoft.DependencyInjection.Tests.csproj b/test/StructureMap.Microsoft.DependencyInjection.Tests/StructureMap.Microsoft.DependencyInjection.Tests.csproj index cc9e563..16a9cad 100644 --- a/test/StructureMap.Microsoft.DependencyInjection.Tests/StructureMap.Microsoft.DependencyInjection.Tests.csproj +++ b/test/StructureMap.Microsoft.DependencyInjection.Tests/StructureMap.Microsoft.DependencyInjection.Tests.csproj @@ -14,7 +14,7 @@ - - + + diff --git a/test/StructureMap.Microsoft.DependencyInjection.Tests/StructureMapContainerTests.cs b/test/StructureMap.Microsoft.DependencyInjection.Tests/StructureMapContainerTests.cs index 7793b2b..5c9156b 100644 --- a/test/StructureMap.Microsoft.DependencyInjection.Tests/StructureMapContainerTests.cs +++ b/test/StructureMap.Microsoft.DependencyInjection.Tests/StructureMapContainerTests.cs @@ -12,6 +12,8 @@ namespace StructureMap.Microsoft.DependencyInjection.Tests { public class StructureMapContainerTests : DependencyInjectionSpecificationTests { + public override bool SupportsIServiceProviderIsService => false; + // The following tests don't pass with the SM adapter... private static readonly string[] SkippedTests = { From da170cac70609cbf9e3e76515080554bf77f14e0 Mon Sep 17 00:00:00 2001 From: Keith Dahlby Date: Thu, 5 Jun 2025 12:54:16 -0500 Subject: [PATCH 2/4] Implement IServiceProviderIsService --- .../ContainerExtensions.cs | 5 +++ .../StructureMapServiceProviderIsService.cs | 44 +++++++++++++++++++ .../StructureMapContainerTests.cs | 12 ++++- 3 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 src/StructureMap.Microsoft.DependencyInjection/StructureMapServiceProviderIsService.cs diff --git a/src/StructureMap.Microsoft.DependencyInjection/ContainerExtensions.cs b/src/StructureMap.Microsoft.DependencyInjection/ContainerExtensions.cs index f917a8e..9e361ab 100644 --- a/src/StructureMap.Microsoft.DependencyInjection/ContainerExtensions.cs +++ b/src/StructureMap.Microsoft.DependencyInjection/ContainerExtensions.cs @@ -137,6 +137,11 @@ public static void Register(this IProfileRegistry registry, IEnumerable(); + // Added in MEDI v6 + registry.For() + .LifecycleIs(Lifecycles.Container) + .UseIfNone(); + foreach (var descriptor in descriptors) { registry.Register(descriptor); diff --git a/src/StructureMap.Microsoft.DependencyInjection/StructureMapServiceProviderIsService.cs b/src/StructureMap.Microsoft.DependencyInjection/StructureMapServiceProviderIsService.cs new file mode 100644 index 0000000..4a05b07 --- /dev/null +++ b/src/StructureMap.Microsoft.DependencyInjection/StructureMapServiceProviderIsService.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using Microsoft.Extensions.DependencyInjection; + +namespace StructureMap +{ + public sealed class StructureMapServiceProviderIsService : IServiceProviderIsService + { + private readonly IContainer _container; + + public StructureMapServiceProviderIsService(IContainer container) => _container = container; + + // https://github.com/dotnet/dotnet/blob/d25d3482f4c3c509977cc4d959c80cb78b6ad9c8/src/runtime/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CallSiteFactory.cs#L778-L803 + public bool IsService(Type serviceType) + { + if (serviceType is null) + { + throw new ArgumentNullException(nameof(serviceType)); + } + + // Querying for an open generic should return false (they aren't resolvable) + if (serviceType.IsGenericTypeDefinition) + { + return false; + } + + if (_container.Model.HasDefaultImplementationFor(serviceType)) + { + return true; + } + + + if (serviceType.IsConstructedGenericType && serviceType.GetGenericTypeDefinition() is Type genericDefinition) + { + // We special case IEnumerable since it isn't explicitly registered in the container + // yet we can manifest instances of it when requested. + return genericDefinition == typeof(IEnumerable<>) || + _container.Model.HasDefaultImplementationFor(genericDefinition); + } + + return false; + } + } +} diff --git a/test/StructureMap.Microsoft.DependencyInjection.Tests/StructureMapContainerTests.cs b/test/StructureMap.Microsoft.DependencyInjection.Tests/StructureMapContainerTests.cs index 5c9156b..1e40845 100644 --- a/test/StructureMap.Microsoft.DependencyInjection.Tests/StructureMapContainerTests.cs +++ b/test/StructureMap.Microsoft.DependencyInjection.Tests/StructureMapContainerTests.cs @@ -12,8 +12,6 @@ namespace StructureMap.Microsoft.DependencyInjection.Tests { public class StructureMapContainerTests : DependencyInjectionSpecificationTests { - public override bool SupportsIServiceProviderIsService => false; - // The following tests don't pass with the SM adapter... private static readonly string[] SkippedTests = { @@ -61,6 +59,14 @@ public void ConfigureAndRegisterDoNotPreventPopulate() Assert.NotNull(container.GetInstance()); Assert.NotNull(container.GetInstance()); Assert.NotNull(container.GetInstance()); + + var spis = container.GetInstance(); + Assert.True(spis.IsService(typeof(IFakeService))); + Assert.True(spis.IsService(typeof(IFakeScopedService))); + Assert.True(spis.IsService(typeof(IFakeSingletonService))); + + Assert.False(spis.IsService(typeof(FakeService))); + Assert.False(spis.IsService(typeof(IFakeServiceInstance))); } [Fact] @@ -77,6 +83,7 @@ public void ConfigureDoesNotRequirePopulate() Assert.NotNull(container.GetInstance()); Assert.NotNull(container.GetInstance()); + Assert.NotNull(container.GetInstance()); Assert.NotNull(container.GetInstance()); } @@ -95,6 +102,7 @@ public void RegisterDoesNotRequirePopulate() Assert.NotNull(container.GetInstance()); Assert.NotNull(container.GetInstance()); + Assert.NotNull(container.GetInstance()); Assert.NotNull(container.GetInstance()); } From e88ea87aa79e5aadfe17c6628b8bb07afa128bf3 Mon Sep 17 00:00:00 2001 From: Keith Dahlby Date: Fri, 13 Jun 2025 16:01:25 -0500 Subject: [PATCH 3/4] Remove redundant generic check --- .../StructureMapServiceProviderIsService.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/StructureMap.Microsoft.DependencyInjection/StructureMapServiceProviderIsService.cs b/src/StructureMap.Microsoft.DependencyInjection/StructureMapServiceProviderIsService.cs index 4a05b07..3461c64 100644 --- a/src/StructureMap.Microsoft.DependencyInjection/StructureMapServiceProviderIsService.cs +++ b/src/StructureMap.Microsoft.DependencyInjection/StructureMapServiceProviderIsService.cs @@ -29,13 +29,11 @@ public bool IsService(Type serviceType) return true; } - if (serviceType.IsConstructedGenericType && serviceType.GetGenericTypeDefinition() is Type genericDefinition) { // We special case IEnumerable since it isn't explicitly registered in the container // yet we can manifest instances of it when requested. - return genericDefinition == typeof(IEnumerable<>) || - _container.Model.HasDefaultImplementationFor(genericDefinition); + return genericDefinition == typeof(IEnumerable<>); } return false; From 0890ecb4c57e8f8df74de8fae06b21f3e6c8c0b2 Mon Sep 17 00:00:00 2001 From: Keith Dahlby Date: Mon, 16 Jun 2025 13:44:38 -0500 Subject: [PATCH 4/4] Add generic asserts --- .../StructureMapContainerTests.cs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/test/StructureMap.Microsoft.DependencyInjection.Tests/StructureMapContainerTests.cs b/test/StructureMap.Microsoft.DependencyInjection.Tests/StructureMapContainerTests.cs index 1e40845..8a1a9c8 100644 --- a/test/StructureMap.Microsoft.DependencyInjection.Tests/StructureMapContainerTests.cs +++ b/test/StructureMap.Microsoft.DependencyInjection.Tests/StructureMapContainerTests.cs @@ -43,6 +43,7 @@ public void ConfigureAndRegisterDoNotPreventPopulate() { var services = new ServiceCollection(); services.AddTransient(); + services.AddSingleton>(StringComparer.OrdinalIgnoreCase); var container = new Container(); container.Configure(config => @@ -67,6 +68,25 @@ public void ConfigureAndRegisterDoNotPreventPopulate() Assert.False(spis.IsService(typeof(FakeService))); Assert.False(spis.IsService(typeof(IFakeServiceInstance))); + + // Open generics never resolve + Assert.False(spis.IsService(typeof(IComparer<>))); + Assert.False(spis.IsService(typeof(IEnumerable<>))); + + // Registered closed generic does resolve + Assert.True(spis.IsService(typeof(IComparer))); + + // Unregistered closed generic does not resolve + Assert.False(spis.IsService(typeof(IComparer))); + + // IEnumerable<> of registered types does resolve + Assert.True(spis.IsService(typeof(IEnumerable))); + Assert.True(spis.IsService(typeof(IEnumerable))); + Assert.True(spis.IsService(typeof(IEnumerable))); + + // IEnumerable<> of unregistered types also resolves + Assert.True(spis.IsService(typeof(IEnumerable))); + Assert.True(spis.IsService(typeof(IEnumerable))); } [Fact]