Ensure that other IoC containers don't dispose things multiple times

Fixes #16
This commit is contained in:
Antony Male 2016-11-25 17:04:50 +00:00
parent 3fd89871b3
commit 9e9514a795
14 changed files with 219 additions and 139 deletions

View File

@ -38,11 +38,11 @@ namespace Bootstrappers
};
builder.RegisterInstance<IViewManager>(new ViewManager(viewManagerConfig));
builder.RegisterInstance<IWindowManagerConfig>(this);
builder.RegisterInstance<IWindowManagerConfig>(this).ExternallyOwned();
builder.RegisterType<WindowManager>().As<IWindowManager>().SingleInstance();
builder.RegisterType<EventAggregator>().As<IEventAggregator>().SingleInstance();
builder.RegisterType<MessageBoxViewModel>().As<IMessageBoxViewModel>(); // Not singleton!
builder.RegisterAssemblyTypes(this.GetType().Assembly);
builder.RegisterType<MessageBoxViewModel>().As<IMessageBoxViewModel>().ExternallyOwned(); // Not singleton!
builder.RegisterAssemblyTypes(this.GetType().Assembly).ExternallyOwned();
}
/// <summary>

View File

@ -30,8 +30,9 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Autofac">
<HintPath>packages\Autofac.3.5.2\lib\net40\Autofac.dll</HintPath>
<Reference Include="Autofac, Version=4.2.1.0, Culture=neutral, PublicKeyToken=17863af14b0044da, processorArchitecture=MSIL">
<HintPath>packages\Autofac.4.2.1\lib\net45\Autofac.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Castle.Core, Version=3.3.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
<HintPath>packages\Castle.Core.3.3.3\lib\net45\Castle.Core.dll</HintPath>
@ -52,24 +53,8 @@
<Reference Include="Ninject">
<HintPath>packages\Ninject.3.2.2.0\lib\net45-full\Ninject.dll</HintPath>
</Reference>
<Reference Include="nunit.core, Version=2.6.4.14350, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL">
<HintPath>packages\NUnitTestAdapter.2.0.0\lib\nunit.core.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="nunit.core.interfaces, Version=2.6.4.14350, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL">
<HintPath>packages\NUnitTestAdapter.2.0.0\lib\nunit.core.interfaces.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="nunit.framework, Version=2.6.4.14350, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL">
<HintPath>packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="nunit.util, Version=2.6.4.14350, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL">
<HintPath>packages\NUnitTestAdapter.2.0.0\lib\nunit.util.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="NUnit.VisualStudio.TestAdapter, Version=2.0.0.0, Culture=neutral, PublicKeyToken=4cb40d35494691ac, processorArchitecture=MSIL">
<HintPath>packages\NUnitTestAdapter.2.0.0\lib\NUnit.VisualStudio.TestAdapter.dll</HintPath>
<Reference Include="nunit.framework, Version=3.5.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
<HintPath>packages\NUnit.3.5.0\lib\net45\nunit.framework.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="PresentationFramework" />

View File

@ -1,5 +1,6 @@
using Castle.Facilities.TypedFactory;
using Castle.MicroKernel.Registration;
using Castle.MicroKernel.Releasers;
using Castle.Windsor;
using Stylet;
using System;
@ -36,6 +37,15 @@ namespace Bootstrappers
ViewFactory = this.GetInstance,
ViewAssemblies = new List<Assembly>() { this.GetType().Assembly }
};
// Stylet does its own disposal of ViewModels: Castle Windsor shouldn't be doing the same
// Castle Windsor seems to be ver opinionated on this point, insisting that the container
// should be responsible for disposing all components. This is at odds with Stylet's approach
// (and indeed common sense).
#pragma warning disable CS0618 // Type or member is obsolete
container.Kernel.ReleasePolicy = new NoTrackingReleasePolicy();
#pragma warning restore CS0618 // Type or member is obsolete
container.Register(
Component.For<IViewManager>().Instance(new ViewManager(viewManagerConfig)),
Component.For<IWindowManagerConfig>().Instance(this),

View File

@ -36,7 +36,7 @@ namespace Bootstrappers
};
kernel.Bind<IViewManager>().ToConstant(new ViewManager(viewManagerConfig));
kernel.Bind<IWindowManagerConfig>().ToConstant(this);
kernel.Bind<IWindowManagerConfig>().ToConstant(this).InTransientScope();
kernel.Bind<IWindowManager>().ToMethod(c => new WindowManager(c.Kernel.Get<IViewManager>(), () => c.Kernel.Get<IMessageBoxViewModel>(), c.Kernel.Get<IWindowManagerConfig>())).InSingletonScope();
kernel.Bind<IEventAggregator>().To<EventAggregator>().InSingletonScope();
kernel.Bind<IMessageBoxViewModel>().To<MessageBoxViewModel>(); // Not singleton!

View File

@ -39,7 +39,8 @@ namespace Bootstrappers
};
config.For<IViewManager>().Add(new ViewManager(viewManagerConfig));
config.For<IWindowManagerConfig>().Add(this);
// Trick it into not taking ownership of (and disposing) the instance
config.For<IWindowManagerConfig>().Add(c => this).LifecycleIs<UniquePerRequestLifecycle>();
config.For<IWindowManager>().Add<WindowManager>().LifecycleIs<SingletonLifecycle>();
config.For<IEventAggregator>().Add<EventAggregator>().LifecycleIs<SingletonLifecycle>();
config.For<IMessageBoxViewModel>().Add<MessageBoxViewModel>().LifecycleIs<UniquePerRequestLifecycle>();

View File

@ -12,6 +12,8 @@ namespace Bootstrappers.Tests
{
public List<string> ConfigureLog { get; set; }
public int DisposeCount { get; private set; }
public MyAutofacBootstrapper()
{
this.ConfigureLog = new List<string>();
@ -44,6 +46,12 @@ namespace Bootstrappers.Tests
{
base.ConfigureBootstrapper();
}
public override void Dispose()
{
base.Dispose();
this.DisposeCount++;
}
}
[TestFixture(Category = "Autofac")]

View File

@ -12,12 +12,13 @@ namespace Bootstrappers.Tests
public interface ITestBootstrapper
{
int DisposeCount { get; }
object GetInstance(Type type);
void ConfigureBootstrapper();
List<string> ConfigureLog { get; }
}
public abstract class BootstrapperTests<TBootstrapper> where TBootstrapper : ITestBootstrapper
public abstract class BootstrapperTests<TBootstrapper> where TBootstrapper : ITestBootstrapper, IDisposable
{
protected TBootstrapper bootstrapper;
@ -125,5 +126,29 @@ namespace Bootstrappers.Tests
Assert.NotNull(vm1);
Assert.AreNotEqual(vm1, vm2);
}
[Test]
public void DoesNotMultiplyDisposeWindowManagerConfig()
{
// The bootstrapper implements the IWindowManagerConfig. Fetch the IWindowManager to force the
// IWindowManagerConfig to be constructed, then dispose the bootstrapper, and make sure that
// the container doesn't dispose the IWindowManagerConfig again
var windowManager = this.bootstrapper.GetInstance(typeof(IWindowManager));
this.bootstrapper.Dispose();
Assert.AreEqual(1, this.bootstrapper.DisposeCount);
}
[Test]
public void DoesNotDisposeTransientInstances()
{
StubType.Reset();
var vm = this.bootstrapper.GetInstance(typeof(StubType));
this.bootstrapper.Dispose();
Assert.AreEqual(0, StubType.DisposeCount);
}
}
}

View File

@ -12,6 +12,8 @@ namespace Bootstrappers.Tests
{
public List<string> ConfigureLog { get; set; }
public int DisposeCount { get; private set; }
public MyCastleWindsorBootstrapper()
{
this.ConfigureLog = new List<string>();
@ -44,6 +46,12 @@ namespace Bootstrappers.Tests
{
base.ConfigureBootstrapper();
}
public override void Dispose()
{
base.Dispose();
this.DisposeCount++;
}
}
[TestFixture(Category = "Castle Windsor")]

View File

@ -12,6 +12,8 @@ namespace Bootstrappers.Tests
{
public List<string> ConfigureLog { get; set; }
public int DisposeCount { get; private set; }
public MyNinjectBootstrapper()
{
this.ConfigureLog = new List<string>();
@ -44,6 +46,12 @@ namespace Bootstrappers.Tests
{
base.ConfigureBootstrapper();
}
public override void Dispose()
{
base.Dispose();
this.DisposeCount++;
}
}
[TestFixture(Category="Ninject")]

View File

@ -11,6 +11,8 @@ namespace Bootstrappers.Tests
{
public List<string> ConfigureLog { get; set; }
public int DisposeCount { get; private set; }
public MyNoIocContainerBootstrapper()
{
this.ConfigureLog = new List<string>();
@ -48,6 +50,12 @@ namespace Bootstrappers.Tests
{
base.ConfigureBootstrapper();
}
public override void Dispose()
{
base.Dispose();
this.DisposeCount++;
}
}
[TestFixture(Category = "NoIoCContainer")]

View File

@ -12,6 +12,8 @@ namespace Bootstrappers.Tests
{
public List<string> ConfigureLog { get; set; }
public int DisposeCount { get; private set; }
public MyStructureMapBootstrapper()
{
this.ConfigureLog = new List<string>();
@ -44,6 +46,12 @@ namespace Bootstrappers.Tests
{
base.ConfigureBootstrapper();
}
public override void Dispose()
{
base.Dispose();
this.DisposeCount++;
}
}
[TestFixture(Category = "StructureMap")]

View File

@ -6,7 +6,18 @@ using System.Threading.Tasks;
namespace Bootstrappers.Tests
{
public class StubType
public class StubType : IDisposable
{
public static int DisposeCount { get; private set; }
public static void Reset()
{
DisposeCount = 0;
}
public void Dispose()
{
DisposeCount++;
}
}
}

View File

@ -12,6 +12,8 @@ namespace Bootstrappers.Tests
{
public List<string> ConfigureLog { get; set; }
public int DisposeCount { get; private set; }
public MyUnityBootstrapper()
{
this.ConfigureLog = new List<string>();
@ -44,6 +46,12 @@ namespace Bootstrappers.Tests
{
base.ConfigureBootstrapper();
}
public override void Dispose()
{
base.Dispose();
this.DisposeCount++;
}
}
[TestFixture(Category = "Unity")]

View File

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Autofac" version="3.5.2" targetFramework="net45" />
<package id="Autofac" version="4.2.1" targetFramework="net45" />
<package id="Castle.Core" version="3.3.3" targetFramework="net45" />
<package id="Castle.Windsor" version="3.3.0" targetFramework="net45" />
<package id="Ninject" version="3.2.2.0" targetFramework="net45" />
<package id="NUnit" version="2.6.4" targetFramework="net45" />
<package id="NUnitTestAdapter" version="2.0.0" targetFramework="net45" />
<package id="NUnit" version="3.5.0" targetFramework="net45" />
<package id="NUnit3TestAdapter" version="3.6.0" targetFramework="net45" />
<package id="structuremap" version="3.1.6.186" targetFramework="net45" />
<package id="Unity" version="3.5.1404.0" targetFramework="net45" />
</packages>