Skip to content

Commit 957098b

Browse files
authored
Public Register() + new Configure() (#2)
* Enhance Populate() docs * Make Register() public * Add Configure() helpers * Add test for Configure/Register
1 parent cfc1322 commit 957098b

3 files changed

Lines changed: 66 additions & 11 deletions

File tree

src/StructureMap.Microsoft.DependencyInjection/ContainerExtensions.cs

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -63,21 +63,19 @@ public static void Populate(this ConfigurationExpression config, IEnumerable<Ser
6363
((Registry) config).Populate(descriptors, checkDuplicateCalls);
6464
}
6565

66-
/// <summary>
67-
/// Populates the registry using the specified service descriptors.
68-
/// </summary>
69-
/// <remarks>
70-
/// This method should only be called once per container.
71-
/// </remarks>
72-
/// <param name="registry">The registry.</param>
73-
/// <param name="descriptors">The service descriptors.</param>
66+
/// <inheritdoc cref="Populate(Registry, IEnumerable{ServiceDescriptor}, bool)"/>
7467
public static void Populate(this Registry registry, IEnumerable<ServiceDescriptor> descriptors)
7568
{
7669
registry.Populate(descriptors, checkDuplicateCalls: false);
7770
}
7871

7972
/// <summary>
80-
/// Populates the registry using the specified service descriptors.
73+
/// Populates the registry using the specified service descriptors, plus:
74+
/// <list type="bullet">
75+
/// <item><see cref="AspNetConstructorSelector"/></item>
76+
/// <item><see cref="StructureMapServiceProvider"/> as per-container <see cref="IServiceProvider"/></item>
77+
/// <item><see cref="StructureMapServiceScopeFactory"/> as per-container <see cref="IServiceScopeFactory"/></item>
78+
/// </list>
8179
/// </summary>
8280
/// <remarks>
8381
/// This method should only be called once per container.
@@ -116,7 +114,26 @@ private static void ThrowIfMarkerInterfaceIsRegistered(PluginGraph graph)
116114
}
117115
}
118116

119-
private static void Register(this IProfileRegistry registry, IEnumerable<ServiceDescriptor> descriptors)
117+
/// <summary>
118+
/// Configures <paramref name="registry"/> with <paramref name="configure"/>.
119+
/// </summary>
120+
/// <remarks>
121+
/// Unlike <see cref="Populate(Registry, IEnumerable{ServiceDescriptor})"/>, this method may be be called more than once per container.
122+
/// </remarks>
123+
/// <param name="registry">The registry.</param>
124+
/// <param name="configure">The service configurator.</param>
125+
public static void Configure(this IProfileRegistry registry, Func<IServiceCollection, IServiceCollection> configure) =>
126+
registry.Register(configure(new SimpleServiceCollection()));
127+
128+
/// <summary>
129+
/// Registers the specified service descriptors.
130+
/// </summary>
131+
/// <remarks>
132+
/// Unlike <see cref="Populate(Registry, IEnumerable{ServiceDescriptor})"/>, this method may be be called more than once per container.
133+
/// </remarks>
134+
/// <param name="registry">The registry.</param>
135+
/// <param name="descriptors">The service descriptors.</param>
136+
public static void Register(this IProfileRegistry registry, IEnumerable<ServiceDescriptor> descriptors)
120137
{
121138
foreach (var descriptor in descriptors)
122139
{
@@ -155,5 +172,11 @@ private static Expression<Func<IContext, object>> CreateFactory(this ServiceDesc
155172
}
156173

157174
private interface IMarkerInterface { }
175+
176+
// We don't depend on the package that declares ServiceCollection,
177+
// but even if we did this is slightly better because we don't need its IsReadOnly checks
178+
private class SimpleServiceCollection : List<ServiceDescriptor>, IServiceCollection
179+
{
180+
}
158181
}
159182
}

src/StructureMap.Microsoft.DependencyInjection/ServiceCollectionExtensions.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using Microsoft.Extensions.DependencyInjection;
1+
using System;
2+
using Microsoft.Extensions.DependencyInjection;
23

34
namespace StructureMap
45
{
@@ -13,5 +14,13 @@ public static IServiceCollection AddStructureMap(this IServiceCollection service
1314
{
1415
return services.AddSingleton<IServiceProviderFactory<Registry>>(new StructureMapServiceProviderFactory(registry));
1516
}
17+
18+
/// <summary>
19+
/// Configures <paramref name="services"/> with <paramref name="configure"/>.
20+
/// </summary>
21+
/// <param name="services">The service collection.</param>
22+
/// <param name="configure">The service configurator.</param>
23+
/// <returns>The result of <paramref name="configure"/>, which should be <paramref name="services"/>.</returns>
24+
public static IServiceCollection Configure(this IServiceCollection services, Func<IServiceCollection, IServiceCollection> configure) => configure(services);
1625
}
1726
}

test/StructureMap.Microsoft.DependencyInjection.Tests/StructureMapContainerTests.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,29 @@ protected override IServiceProvider CreateServiceProvider(IServiceCollection ser
3838
return container.GetInstance<IServiceProvider>();
3939
}
4040

41+
[Fact]
42+
public void ConfigureAndRegisterDoNotPreventPopulate()
43+
{
44+
var services = new ServiceCollection();
45+
services.AddTransient<IFakeService, FakeService>();
46+
47+
var container = new Container();
48+
container.Configure(config =>
49+
{
50+
config.Register(services);
51+
config.Register(services);
52+
53+
config.Configure(ctx => ctx.AddScoped<IFakeScopedService, FakeService>());
54+
config.Configure(ctx => ctx.AddSingleton<IFakeSingletonService, FakeService>());
55+
56+
config.Populate(services, checkDuplicateCalls: true);
57+
});
58+
59+
Assert.NotNull(container.GetInstance<IFakeService>());
60+
Assert.NotNull(container.GetInstance<IFakeSingletonService>());
61+
Assert.NotNull(container.GetInstance<IFakeScopedService>());
62+
}
63+
4164
[Theory]
4265
[InlineData(true)]
4366
[InlineData(false)]

0 commit comments

Comments
 (0)