From 9e9514a7953d364180ced53227071bd737cac82e Mon Sep 17 00:00:00 2001 From: Antony Male Date: Fri, 25 Nov 2016 17:04:50 +0000 Subject: [PATCH] Ensure that other IoC containers don't dispose things multiple times Fixes #16 --- Bootstrappers/AutofacBootstrapper.cs | 6 +- Bootstrappers/Bootstrappers.csproj | 229 ++++++++++----------- Bootstrappers/CastleWindsorBootstrapper.cs | 10 + Bootstrappers/NinjectBootstrapper.cs | 2 +- Bootstrappers/StructureMapBootstrapper.cs | 3 +- Bootstrappers/Tests/AutofacTests.cs | 8 + Bootstrappers/Tests/BootstrapperTests.cs | 27 ++- Bootstrappers/Tests/CastleWindsorTests.cs | 8 + Bootstrappers/Tests/NinjectTests.cs | 8 + Bootstrappers/Tests/NoIoCContainerTests.cs | 8 + Bootstrappers/Tests/StructureMapTests.cs | 8 + Bootstrappers/Tests/StubType.cs | 13 +- Bootstrappers/Tests/UnityTests.cs | 8 + Bootstrappers/packages.config | 20 +- 14 files changed, 219 insertions(+), 139 deletions(-) diff --git a/Bootstrappers/AutofacBootstrapper.cs b/Bootstrappers/AutofacBootstrapper.cs index 72a0493..e06b12f 100644 --- a/Bootstrappers/AutofacBootstrapper.cs +++ b/Bootstrappers/AutofacBootstrapper.cs @@ -38,11 +38,11 @@ namespace Bootstrappers }; builder.RegisterInstance(new ViewManager(viewManagerConfig)); - builder.RegisterInstance(this); + builder.RegisterInstance(this).ExternallyOwned(); builder.RegisterType().As().SingleInstance(); builder.RegisterType().As().SingleInstance(); - builder.RegisterType().As(); // Not singleton! - builder.RegisterAssemblyTypes(this.GetType().Assembly); + builder.RegisterType().As().ExternallyOwned(); // Not singleton! + builder.RegisterAssemblyTypes(this.GetType().Assembly).ExternallyOwned(); } /// diff --git a/Bootstrappers/Bootstrappers.csproj b/Bootstrappers/Bootstrappers.csproj index abf6554..1ccd9ff 100644 --- a/Bootstrappers/Bootstrappers.csproj +++ b/Bootstrappers/Bootstrappers.csproj @@ -1,129 +1,114 @@ - - - - - Debug - AnyCPU - {E37E66CD-04DE-4D48-AC90-26B331C1E7C0} - Library - Properties - Bootstrappers - Bootstrappers - v4.5 - 512 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - packages\Autofac.3.5.2\lib\net40\Autofac.dll - - - packages\Castle.Core.3.3.3\lib\net45\Castle.Core.dll - True - - - packages\Castle.Windsor.3.3.0\lib\net45\Castle.Windsor.dll - - - packages\Unity.3.5.1404.0\lib\net45\Microsoft.Practices.Unity.dll - - - packages\Unity.3.5.1404.0\lib\net45\Microsoft.Practices.Unity.Configuration.dll - - - packages\Unity.3.5.1404.0\lib\net45\Microsoft.Practices.Unity.RegistrationByConvention.dll - - - packages\Ninject.3.2.2.0\lib\net45-full\Ninject.dll - - - packages\NUnitTestAdapter.2.0.0\lib\nunit.core.dll - True - - - packages\NUnitTestAdapter.2.0.0\lib\nunit.core.interfaces.dll - True - - - packages\NUnit.2.6.4\lib\nunit.framework.dll - True - - - packages\NUnitTestAdapter.2.0.0\lib\nunit.util.dll - True - - - packages\NUnitTestAdapter.2.0.0\lib\NUnit.VisualStudio.TestAdapter.dll - True - - - - packages\structuremap.3.1.6.186\lib\net40\StructureMap.dll - True - - - packages\structuremap.3.1.6.186\lib\net40\StructureMap.Net4.dll - True - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {2435bd00-ac12-48b0-ad36-9bab2fdec3f5} - Stylet - - - + + + + + Debug + AnyCPU + {E37E66CD-04DE-4D48-AC90-26B331C1E7C0} + Library + Properties + Bootstrappers + Bootstrappers + v4.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + packages\Autofac.4.2.1\lib\net45\Autofac.dll + True + + + packages\Castle.Core.3.3.3\lib\net45\Castle.Core.dll + True + + + packages\Castle.Windsor.3.3.0\lib\net45\Castle.Windsor.dll + + + packages\Unity.3.5.1404.0\lib\net45\Microsoft.Practices.Unity.dll + + + packages\Unity.3.5.1404.0\lib\net45\Microsoft.Practices.Unity.Configuration.dll + + + packages\Unity.3.5.1404.0\lib\net45\Microsoft.Practices.Unity.RegistrationByConvention.dll + + + packages\Ninject.3.2.2.0\lib\net45-full\Ninject.dll + + + packages\NUnit.3.5.0\lib\net45\nunit.framework.dll + True + + + + packages\structuremap.3.1.6.186\lib\net40\StructureMap.dll + True + + + packages\structuremap.3.1.6.186\lib\net40\StructureMap.Net4.dll + True + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {2435bd00-ac12-48b0-ad36-9bab2fdec3f5} + Stylet + + + + --> \ No newline at end of file diff --git a/Bootstrappers/CastleWindsorBootstrapper.cs b/Bootstrappers/CastleWindsorBootstrapper.cs index 25dfd1c..5fd286f 100644 --- a/Bootstrappers/CastleWindsorBootstrapper.cs +++ b/Bootstrappers/CastleWindsorBootstrapper.cs @@ -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() { 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().Instance(new ViewManager(viewManagerConfig)), Component.For().Instance(this), diff --git a/Bootstrappers/NinjectBootstrapper.cs b/Bootstrappers/NinjectBootstrapper.cs index bd91805..2427b91 100644 --- a/Bootstrappers/NinjectBootstrapper.cs +++ b/Bootstrappers/NinjectBootstrapper.cs @@ -36,7 +36,7 @@ namespace Bootstrappers }; kernel.Bind().ToConstant(new ViewManager(viewManagerConfig)); - kernel.Bind().ToConstant(this); + kernel.Bind().ToConstant(this).InTransientScope(); kernel.Bind().ToMethod(c => new WindowManager(c.Kernel.Get(), () => c.Kernel.Get(), c.Kernel.Get())).InSingletonScope(); kernel.Bind().To().InSingletonScope(); kernel.Bind().To(); // Not singleton! diff --git a/Bootstrappers/StructureMapBootstrapper.cs b/Bootstrappers/StructureMapBootstrapper.cs index fd3bc5e..cde9cf1 100644 --- a/Bootstrappers/StructureMapBootstrapper.cs +++ b/Bootstrappers/StructureMapBootstrapper.cs @@ -39,7 +39,8 @@ namespace Bootstrappers }; config.For().Add(new ViewManager(viewManagerConfig)); - config.For().Add(this); + // Trick it into not taking ownership of (and disposing) the instance + config.For().Add(c => this).LifecycleIs(); config.For().Add().LifecycleIs(); config.For().Add().LifecycleIs(); config.For().Add().LifecycleIs(); diff --git a/Bootstrappers/Tests/AutofacTests.cs b/Bootstrappers/Tests/AutofacTests.cs index 49a0c37..3ee1dae 100644 --- a/Bootstrappers/Tests/AutofacTests.cs +++ b/Bootstrappers/Tests/AutofacTests.cs @@ -12,6 +12,8 @@ namespace Bootstrappers.Tests { public List ConfigureLog { get; set; } + public int DisposeCount { get; private set; } + public MyAutofacBootstrapper() { this.ConfigureLog = new List(); @@ -44,6 +46,12 @@ namespace Bootstrappers.Tests { base.ConfigureBootstrapper(); } + + public override void Dispose() + { + base.Dispose(); + this.DisposeCount++; + } } [TestFixture(Category = "Autofac")] diff --git a/Bootstrappers/Tests/BootstrapperTests.cs b/Bootstrappers/Tests/BootstrapperTests.cs index 642fc76..9308844 100644 --- a/Bootstrappers/Tests/BootstrapperTests.cs +++ b/Bootstrappers/Tests/BootstrapperTests.cs @@ -12,12 +12,13 @@ namespace Bootstrappers.Tests public interface ITestBootstrapper { + int DisposeCount { get; } object GetInstance(Type type); void ConfigureBootstrapper(); List ConfigureLog { get; } } - public abstract class BootstrapperTests where TBootstrapper : ITestBootstrapper + public abstract class BootstrapperTests 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); + + } } } diff --git a/Bootstrappers/Tests/CastleWindsorTests.cs b/Bootstrappers/Tests/CastleWindsorTests.cs index 2ebca39..f58d03c 100644 --- a/Bootstrappers/Tests/CastleWindsorTests.cs +++ b/Bootstrappers/Tests/CastleWindsorTests.cs @@ -12,6 +12,8 @@ namespace Bootstrappers.Tests { public List ConfigureLog { get; set; } + public int DisposeCount { get; private set; } + public MyCastleWindsorBootstrapper() { this.ConfigureLog = new List(); @@ -44,6 +46,12 @@ namespace Bootstrappers.Tests { base.ConfigureBootstrapper(); } + + public override void Dispose() + { + base.Dispose(); + this.DisposeCount++; + } } [TestFixture(Category = "Castle Windsor")] diff --git a/Bootstrappers/Tests/NinjectTests.cs b/Bootstrappers/Tests/NinjectTests.cs index 50143a0..a5b627e 100644 --- a/Bootstrappers/Tests/NinjectTests.cs +++ b/Bootstrappers/Tests/NinjectTests.cs @@ -12,6 +12,8 @@ namespace Bootstrappers.Tests { public List ConfigureLog { get; set; } + public int DisposeCount { get; private set; } + public MyNinjectBootstrapper() { this.ConfigureLog = new List(); @@ -44,6 +46,12 @@ namespace Bootstrappers.Tests { base.ConfigureBootstrapper(); } + + public override void Dispose() + { + base.Dispose(); + this.DisposeCount++; + } } [TestFixture(Category="Ninject")] diff --git a/Bootstrappers/Tests/NoIoCContainerTests.cs b/Bootstrappers/Tests/NoIoCContainerTests.cs index ab78c55..9a4bf6e 100644 --- a/Bootstrappers/Tests/NoIoCContainerTests.cs +++ b/Bootstrappers/Tests/NoIoCContainerTests.cs @@ -11,6 +11,8 @@ namespace Bootstrappers.Tests { public List ConfigureLog { get; set; } + public int DisposeCount { get; private set; } + public MyNoIocContainerBootstrapper() { this.ConfigureLog = new List(); @@ -48,6 +50,12 @@ namespace Bootstrappers.Tests { base.ConfigureBootstrapper(); } + + public override void Dispose() + { + base.Dispose(); + this.DisposeCount++; + } } [TestFixture(Category = "NoIoCContainer")] diff --git a/Bootstrappers/Tests/StructureMapTests.cs b/Bootstrappers/Tests/StructureMapTests.cs index 5e263f8..fff71eb 100644 --- a/Bootstrappers/Tests/StructureMapTests.cs +++ b/Bootstrappers/Tests/StructureMapTests.cs @@ -12,6 +12,8 @@ namespace Bootstrappers.Tests { public List ConfigureLog { get; set; } + public int DisposeCount { get; private set; } + public MyStructureMapBootstrapper() { this.ConfigureLog = new List(); @@ -44,6 +46,12 @@ namespace Bootstrappers.Tests { base.ConfigureBootstrapper(); } + + public override void Dispose() + { + base.Dispose(); + this.DisposeCount++; + } } [TestFixture(Category = "StructureMap")] diff --git a/Bootstrappers/Tests/StubType.cs b/Bootstrappers/Tests/StubType.cs index 7e5a4de..c07290f 100644 --- a/Bootstrappers/Tests/StubType.cs +++ b/Bootstrappers/Tests/StubType.cs @@ -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++; + } } } diff --git a/Bootstrappers/Tests/UnityTests.cs b/Bootstrappers/Tests/UnityTests.cs index 9c22a11..684cc40 100644 --- a/Bootstrappers/Tests/UnityTests.cs +++ b/Bootstrappers/Tests/UnityTests.cs @@ -12,6 +12,8 @@ namespace Bootstrappers.Tests { public List ConfigureLog { get; set; } + public int DisposeCount { get; private set; } + public MyUnityBootstrapper() { this.ConfigureLog = new List(); @@ -44,6 +46,12 @@ namespace Bootstrappers.Tests { base.ConfigureBootstrapper(); } + + public override void Dispose() + { + base.Dispose(); + this.DisposeCount++; + } } [TestFixture(Category = "Unity")] diff --git a/Bootstrappers/packages.config b/Bootstrappers/packages.config index 664cd5f..8b5cd13 100644 --- a/Bootstrappers/packages.config +++ b/Bootstrappers/packages.config @@ -1,11 +1,11 @@ - - - - - - - - - - + + + + + + + + + + \ No newline at end of file