Skip to content

Commit

Permalink
Fixed #780: Disposal tracking of provided instances is now consistent…
Browse files Browse the repository at this point in the history
… in root and nested lifetime scopes.
  • Loading branch information
alexmg committed Jul 25, 2017
1 parent bf9cdd9 commit c5e5cfb
Show file tree
Hide file tree
Showing 3 changed files with 185 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,8 @@ internal class ComponentRegistrationLifetimeDecorator : Disposable, IComponentRe

public ComponentRegistrationLifetimeDecorator(IComponentRegistration inner, IComponentLifetime lifetime)
{
if (inner == null) throw new ArgumentNullException(nameof(inner));
if (lifetime == null) throw new ArgumentNullException(nameof(lifetime));

_inner = inner;
Lifetime = lifetime;
_inner = inner ?? throw new ArgumentNullException(nameof(inner));
Lifetime = lifetime ?? throw new ArgumentNullException(nameof(lifetime));
}

public Guid Id => _inner.Id;
Expand All @@ -65,8 +62,8 @@ public ComponentRegistrationLifetimeDecorator(IComponentRegistration inner, ICom

public event EventHandler<PreparingEventArgs> Preparing
{
add { _inner.Preparing += value; }
remove { _inner.Preparing -= value; }
add => _inner.Preparing += value;
remove => _inner.Preparing -= value;
}

public void RaisePreparing(IComponentContext context, ref IEnumerable<Parameter> parameters)
Expand All @@ -76,8 +73,8 @@ public void RaisePreparing(IComponentContext context, ref IEnumerable<Parameter>

public event EventHandler<ActivatingEventArgs<object>> Activating
{
add { _inner.Activating += value; }
remove { _inner.Activating -= value; }
add => _inner.Activating += value;
remove => _inner.Activating -= value;
}

public void RaiseActivating(IComponentContext context, IEnumerable<Parameter> parameters, ref object instance)
Expand All @@ -87,13 +84,18 @@ public void RaiseActivating(IComponentContext context, IEnumerable<Parameter> pa

public event EventHandler<ActivatedEventArgs<object>> Activated
{
add { _inner.Activated += value; }
remove { _inner.Activated -= value; }
add => _inner.Activated += value;
remove => _inner.Activated -= value;
}

public void RaiseActivated(IComponentContext context, IEnumerable<Parameter> parameters, object instance)
{
_inner.RaiseActivated(context, parameters, instance);
}

protected override void Dispose(bool disposing)
{
_inner.Dispose();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using Autofac.Core.Lifetime;
using Autofac.Core.Registration;
using Xunit;

namespace Autofac.Test.Core.Registration
{
public class ComponentRegistrationLifetimeDecoratorTests
{
[Fact]
public void DecoratorCallsDisposeOnInnerInstance()
{
var inner = Mocks.GetComponentRegistration();
var decorator = new ComponentRegistrationLifetimeDecorator(inner, new CurrentScopeLifetime());

decorator.Dispose();

Assert.True(inner.IsDisposed);
}
}
}
163 changes: 152 additions & 11 deletions test/Autofac.Test/IntegrationTests.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using Autofac.Builder;
using Autofac.Core;
using Autofac.Test.Scenarios.Dependencies.Circularity;
using Autofac.Test.Scenarios.Graph1;
Expand All @@ -23,14 +21,14 @@ public void CanCorrectlyBuildGraph1()

var target = builder.Build();

E1 e = target.Resolve<E1>();
A1 a = target.Resolve<A1>();
B1 b = target.Resolve<B1>();
IC1 c = target.Resolve<IC1>();
ID1 d = target.Resolve<ID1>();
var e = target.Resolve<E1>();
var a = target.Resolve<A1>();
var b = target.Resolve<B1>();
var c = target.Resolve<IC1>();
var d = target.Resolve<ID1>();

Assert.IsType<CD1>(c);
CD1 cd = (CD1)c;
var cd = (CD1)c;

Assert.Same(a, b.A);
Assert.Same(a, cd.A);
Expand All @@ -56,18 +54,21 @@ public void DetectsAndIdentifiesCircularDependencies()
}

[Fact]
public void UnresolvedProvidedInstances_DisposedWithLifetimeScope()
public void ResolvedProvidedInstances_DisposedWithLifetimeScope()
{
var builder = new ContainerBuilder();
var disposable = new DisposeTracker();
builder.RegisterInstance(disposable);
var container = builder.Build();
container.Resolve<DisposeTracker>();

container.Dispose();

Assert.True(disposable.IsDisposed);
}

[Fact]
public void ResolvedProvidedInstances_OnlyDisposedOnce()
public void ResolvedProvidedInstances_DisposedWithLifetimeScope_OnlyDisposedOnce()
{
// Issue 383: Disposing a container should only dispose a provided instance one time.
var builder = new ContainerBuilder();
Expand All @@ -77,6 +78,129 @@ public void ResolvedProvidedInstances_OnlyDisposedOnce()
builder.RegisterInstance(disposable);
var container = builder.Build();
container.Resolve<DisposeTracker>();

container.Dispose();

Assert.Equal(1, count);
}

[Fact]
public void ResolvedProvidedInstances_DisposedWithNestedLifetimeScope()
{
var builder = new ContainerBuilder();
var disposable = new DisposeTracker();
var container = builder.Build();
var scope = container.BeginLifetimeScope(b => b.RegisterInstance(disposable));
scope.Resolve<DisposeTracker>();

scope.Dispose();

Assert.True(disposable.IsDisposed);
}

[Fact]
public void ResolvedProvidedInstances_DisposedWithNestedLifetimeScope_OnlyDisposedOnce()
{
// Issue 383: Disposing a container should only dispose a provided instance one time.
var builder = new ContainerBuilder();
var count = 0;
var disposable = new DisposeTracker();
disposable.Disposing += (sender, e) => count++;
var container = builder.Build();
var scope = container.BeginLifetimeScope(b => b.RegisterInstance(disposable));
scope.Resolve<DisposeTracker>();

scope.Dispose();
Assert.Equal(1, count);

container.Dispose();
Assert.Equal(1, count);
}

[Fact]
public void ResolvedProvidedInstances_NotOwnedByLifetimeScope_NeverDisposed()
{
var builder = new ContainerBuilder();
var disposable = new DisposeTracker();
builder.RegisterInstance(disposable).ExternallyOwned();
var container = builder.Build();
container.Resolve<DisposeTracker>();

container.Dispose();

Assert.False(disposable.IsDisposed);
}

[Fact]
public void ResolvedProvidedInstances_NotOwnedByNestedLifetimeScope_NeverDisposed()
{
var builder = new ContainerBuilder();
var disposable = new DisposeTracker();
var container = builder.Build();
var scope = container.BeginLifetimeScope(b => b.RegisterInstance(disposable).ExternallyOwned());
scope.Resolve<DisposeTracker>();

scope.Dispose();
Assert.False(disposable.IsDisposed);

container.Dispose();
Assert.False(disposable.IsDisposed);
}

[Fact]
public void UnresolvedProvidedInstances_DisposedWithLifetimeScope()
{
var builder = new ContainerBuilder();
var disposable = new DisposeTracker();
builder.RegisterInstance(disposable);
var container = builder.Build();

container.Dispose();

Assert.True(disposable.IsDisposed);
}

[Fact]
public void UnresolvedProvidedInstances_DisposedWithLifetimeScope_OnlyDisposedOnce()
{
var builder = new ContainerBuilder();
var count = 0;
var disposable = new DisposeTracker();
disposable.Disposing += (sender, e) => count++;
builder.RegisterInstance(disposable);
var container = builder.Build();

container.Dispose();

Assert.Equal(1, count);
}

[Fact]
public void UnresolvedProvidedInstances_DisposedWithNestedLifetimeScope()
{
var builder = new ContainerBuilder();
var disposable = new DisposeTracker();
var container = builder.Build();
var scope = container.BeginLifetimeScope(b => b.RegisterInstance(disposable));

scope.Dispose();

Assert.True(disposable.IsDisposed);
}

[Fact]
public void UnresolvedProvidedInstances_DisposedWithNestedLifetimeScope_OnlyDisposedOnce()
{
var builder = new ContainerBuilder();
var count = 0;
var disposable = new DisposeTracker();
disposable.Disposing += (sender, e) => count++;
var container = builder.Build();
var scope = container.BeginLifetimeScope(b => b.RegisterInstance(disposable));

scope.Dispose();
Assert.Equal(1, count);

container.Dispose();
Assert.Equal(1, count);
}
Expand All @@ -88,6 +212,23 @@ public void UnresolvedProvidedInstances_NotOwnedByLifetimeScope_NeverDisposed()
var disposable = new DisposeTracker();
builder.RegisterInstance(disposable).ExternallyOwned();
var container = builder.Build();

container.Dispose();

Assert.False(disposable.IsDisposed);
}

[Fact]
public void UnresolvedProvidedInstances_NotOwnedByNestedLifetimeScope_NeverDisposed()
{
var builder = new ContainerBuilder();
var disposable = new DisposeTracker();
var container = builder.Build();
var scope = container.BeginLifetimeScope(b => b.RegisterInstance(disposable).ExternallyOwned());

scope.Dispose();
Assert.False(disposable.IsDisposed);

container.Dispose();
Assert.False(disposable.IsDisposed);
}
Expand Down

0 comments on commit c5e5cfb

Please sign in to comment.