Skip to content

Commit b76e7a5

Browse files
authored
Merge pull request #1451 from nblumhardt/auto-activate-should-not-hide-default
`AutoActivate()` should not hide a component's default service
2 parents 07cac90 + fb6c31b commit b76e7a5

File tree

3 files changed

+40
-21
lines changed

3 files changed

+40
-21
lines changed

src/Autofac/Builder/RegistrationData.cs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public class RegistrationData
1717
private bool _defaultServiceOverridden;
1818
private Service _defaultService;
1919

20-
private readonly ICollection<Service> _services = new HashSet<Service>();
20+
private readonly HashSet<Service> _services = [];
2121

2222
private IComponentLifetime _lifetime = CurrentScopeLifetime.Instance;
2323

@@ -43,12 +43,15 @@ public IEnumerable<Service> Services
4343
{
4444
get
4545
{
46-
if (_defaultServiceOverridden)
46+
if (!_defaultServiceOverridden && !_services.Contains(_defaultService))
4747
{
48-
return _services;
48+
yield return _defaultService;
4949
}
5050

51-
return _services.DefaultIfEmpty(_defaultService);
51+
foreach (var service in _services)
52+
{
53+
yield return service;
54+
}
5255
}
5356
}
5457

@@ -65,11 +68,15 @@ public void AddServices(IEnumerable<Service> services)
6568
throw new ArgumentNullException(nameof(services));
6669
}
6770

68-
_defaultServiceOverridden = true; // important even when services is empty
71+
var empty = true;
6972
foreach (var service in services)
7073
{
74+
empty = false;
7175
AddService(service);
7276
}
77+
78+
// `As([])` clears the default service.
79+
_defaultServiceOverridden = _defaultServiceOverridden || empty;
7380
}
7481

7582
/// <summary>
@@ -83,7 +90,9 @@ public void AddService(Service service)
8390
throw new ArgumentNullException(nameof(service));
8491
}
8592

86-
_defaultServiceOverridden = true;
93+
// `AutoActivateService` is internal plumbing; `AutoActivate()` isn't expected to modify user-visible
94+
// services.
95+
_defaultServiceOverridden = _defaultServiceOverridden || service is not AutoActivateService;
8796
_services.Add(service);
8897
}
8998

src/Autofac/RegistrationExtensions.cs

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,11 @@ public static IRegistrationBuilder<T, SimpleActivatorData, SingleRegistrationSty
6969

7070
rb.SingleInstance();
7171

72+
// https://github.com/autofac/Autofac/issues/1102
73+
// Single instance registrations with any custom activation phases (i.e. activation handlers) need to be auto-activated,
74+
// so that other behavior (such as OnRelease) that expects 'normal' object lifetime behavior works as expected.
75+
rb.RegistrationData.AddService(new AutoActivateService());
76+
7277
rb.RegistrationData.DeferredCallback = builder.RegisterCallback(cr =>
7378
{
7479
if (rb.RegistrationData.Lifetime is not RootScopeLifetime ||
@@ -79,21 +84,6 @@ public static IRegistrationBuilder<T, SimpleActivatorData, SingleRegistrationSty
7984

8085
activator.DisposeInstance = rb.RegistrationData.Ownership == InstanceOwnership.OwnedByLifetimeScope;
8186

82-
// https://github.com/autofac/Autofac/issues/1102
83-
// Single instance registrations with any custom activation phases (i.e. activation handlers) need to be auto-activated,
84-
// so that other behavior (such as OnRelease) that expects 'normal' object lifetime behavior works as expected.
85-
if (rb.ResolvePipeline.Middleware.Any(s => s.Phase == PipelinePhase.Activation))
86-
{
87-
var autoStartService = rb.RegistrationData.Services.First();
88-
89-
var activationRegistration = new RegistrationBuilder<T, SimpleActivatorData, SingleRegistrationStyle>(
90-
new AutoActivateService(),
91-
new SimpleActivatorData(new DelegateActivator(typeof(T), (c, p) => c.ResolveService(autoStartService))),
92-
new SingleRegistrationStyle());
93-
94-
RegistrationBuilder.RegisterSingleComponent(cr, activationRegistration);
95-
}
96-
9787
RegistrationBuilder.RegisterSingleComponent(cr, rb);
9888
});
9989

test/Autofac.Specification.Test/Features/StartableTests.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,26 @@ public void Startable_WhenTheContainerIsBuilt_StartableComponentsThatDependOnAut
168168
Assert.Equal(expectedStartCount, StartableDependency.Count);
169169
}
170170

171+
[Fact]
172+
public void AutoActivate_DoesNotHideDefaultSelfService()
173+
{
174+
var builder = new ContainerBuilder();
175+
builder.RegisterType<MyComponent2>().AutoActivate();
176+
using var container = builder.Build();
177+
Assert.True(container.IsRegistered<MyComponent2>());
178+
}
179+
180+
[Fact]
181+
public void AutoActivate_RegisterInstanceActivationWorksWhenDefaultServiceOverloaded()
182+
{
183+
var instanceCount = 0;
184+
var builder = new ContainerBuilder();
185+
builder.RegisterInstance(new MyComponent2()).As<object>().OnActivated(_ => instanceCount++);
186+
builder.RegisterType<object>();
187+
builder.Build();
188+
Assert.Equal(1, instanceCount);
189+
}
190+
171191
private class ComponentTakesStartableDependency : IStartable
172192
{
173193
public ComponentTakesStartableDependency(StartableTakesDependency dependency, bool expectStarted)

0 commit comments

Comments
 (0)