From: <jer...@us...> - 2009-06-03 17:47:46
|
Revision: 248 http://structuremap.svn.sourceforge.net/structuremap/?rev=248&view=rev Author: jeremydmiller Date: 2009-06-03 17:47:44 +0000 (Wed, 03 Jun 2009) Log Message: ----------- got the dispose working for nested container Modified Paths: -------------- trunk/Source/StructureMap/Container.cs trunk/Source/StructureMap/IContainer.cs trunk/Source/StructureMap/PipelineGraph.cs trunk/Source/StructureMap.Testing/Pipeline/NestedContainerSupportTester.cs trunk/Source/StructureMap.Testing/StructureMap.Testing.csproj Added Paths: ----------- trunk/Source/StructureMap.Testing/Pipeline/ContainerDisposalTester.cs Modified: trunk/Source/StructureMap/Container.cs =================================================================== --- trunk/Source/StructureMap/Container.cs 2009-06-03 16:21:03 UTC (rev 247) +++ trunk/Source/StructureMap/Container.cs 2009-06-03 17:47:44 UTC (rev 248) @@ -134,18 +134,8 @@ return getListOfTypeWithSession<T>(session); } - /// <summary> - /// Injects the given object into a Container as the default for the designated - /// PLUGINTYPE. Mostly used for temporarily setting up return values of the Container - /// to introduce mocks or stubs during automated testing scenarios - /// </summary> - /// <typeparam name="PLUGINTYPE"></typeparam> - /// <param name="instance"></param> - public void Inject<PLUGINTYPE>(PLUGINTYPE instance) - { - _pipelineGraph.Inject(instance); - } + /// <summary> /// Creates or finds the default instance of type T /// </summary> @@ -162,20 +152,8 @@ return (T) FillDependencies(typeof (T)); } - /// <summary> - /// Injects the given object into a Container by name for the designated - /// pluginType. Mostly used for temporarily setting up return values of the Container - /// to introduce mocks or stubs during automated testing scenarios - /// </summary> - /// <typeparam name="T"></typeparam> - /// <param name="name"></param> - /// <param name="stub"></param> - public void Inject<T>(string name, T stub) - { - LiteralInstance instance = new LiteralInstance(stub).WithName(name); - _pipelineGraph.AddInstance<T>(instance); - } + /// <summary> /// Creates or resolves all registered instances of type T /// </summary> @@ -312,26 +290,8 @@ return GetInstance(type); } - /// <summary> - /// Injects the given object into a Container as the default for the designated - /// pluginType. Mostly used for temporarily setting up return values of the Container - /// to introduce mocks or stubs during automated testing scenarios - /// </summary> - /// <param name="pluginType"></param> - /// <param name="stub"></param> - public void Inject(Type pluginType, object stub) - { - if (!CanBeCast(pluginType, stub.GetType())) - { - throw new StructureMapException(220, pluginType.FullName, - stub.GetType().FullName); - } - var instance = new LiteralInstance(stub); - _pipelineGraph.SetDefault(pluginType, instance); - } - /// <summary> /// Creates or resolves all registered instances of the pluginType /// </summary> @@ -470,7 +430,7 @@ /// <returns></returns> public IContainer GetNestedContainer() { - return new Container() + return new Container { _interceptorLibrary = _interceptorLibrary, _pipelineGraph = _pipelineGraph.Clone(), @@ -485,12 +445,17 @@ /// <returns></returns> public IContainer GetNestedContainer(string profileName) { - var container = GetNestedContainer(); + IContainer container = GetNestedContainer(); container.SetDefaultsToProfile(profileName); return container; } + public void Dispose() + { + _transientCache.DisposeAndClear(); + } + #endregion private object buildInstanceWithArgs(Type pluginType, Instance defaultInstance, ExplicitArguments args, @@ -552,16 +517,8 @@ return list; } - /// <summary> - /// Sets the default instance for the PluginType - /// </summary> - /// <param name="pluginType"></param> - /// <param name="instance"></param> - public void Inject(Type pluginType, Instance instance) - { - _pipelineGraph.SetDefault(pluginType, instance); - } + private BuildSession withNewSession(string name) { return new BuildSession(_pipelineGraph, _interceptorLibrary, _transientCache) @@ -615,5 +572,65 @@ } #endregion + + + /// <summary> + /// Injects the given object into a Container by name for the designated + /// pluginType. Mostly used for temporarily setting up return values of the Container + /// to introduce mocks or stubs during automated testing scenarios + /// </summary> + /// <typeparam name="T"></typeparam> + /// <param name="name"></param> + /// <param name="object"></param> + public void Inject<T>(string name, T @object) + { + LiteralInstance instance = new LiteralInstance(@object).WithName(name); + _transientCache.Set(typeof(T), instance, @object); + _pipelineGraph.AddInstance<T>(instance); + } + + /// <summary> + /// Sets the default instance for the PluginType + /// </summary> + /// <param name="pluginType"></param> + /// <param name="instance"></param> + public void Inject(Type pluginType, Instance instance) + { + _pipelineGraph.SetDefault(pluginType, instance); + } + + /// <summary> + /// Injects the given object into a Container as the default for the designated + /// pluginType. Mostly used for temporarily setting up return values of the Container + /// to introduce mocks or stubs during automated testing scenarios + /// </summary> + /// <param name="pluginType"></param> + /// <param name="object"></param> + public void Inject(Type pluginType, object @object) + { + if (!CanBeCast(pluginType, @object.GetType())) + { + throw new StructureMapException(220, pluginType.FullName, + @object.GetType().FullName); + } + + + var instance = new LiteralInstance(@object); + _transientCache.Set(pluginType, instance, @object); + _pipelineGraph.SetDefault(pluginType, instance); + } + + /// <summary> + /// Injects the given object into a Container as the default for the designated + /// PLUGINTYPE. Mostly used for temporarily setting up return values of the Container + /// to introduce mocks or stubs during automated testing scenarios + /// </summary> + /// <typeparam name="PLUGINTYPE"></typeparam> + /// <param name="object"></param> + public void Inject<PLUGINTYPE>(PLUGINTYPE @object) + { + var instance = _pipelineGraph.Inject(@object); + _transientCache.Set(typeof(PLUGINTYPE), instance, @object); + } } } \ No newline at end of file Modified: trunk/Source/StructureMap/IContainer.cs =================================================================== --- trunk/Source/StructureMap/IContainer.cs 2009-06-03 16:21:03 UTC (rev 247) +++ trunk/Source/StructureMap/IContainer.cs 2009-06-03 17:47:44 UTC (rev 248) @@ -9,7 +9,7 @@ /// <summary> /// The main "container" object that implements the Service Locator pattern /// </summary> - public interface IContainer + public interface IContainer : IDisposable { /// <summary> /// Provides queryable access to the configured PluginType's and Instances of this Container @@ -132,8 +132,8 @@ /// to introduce mocks or stubs during automated testing scenarios /// </summary> /// <param name="pluginType"></param> - /// <param name="stub"></param> - void Inject(Type pluginType, object stub); + /// <param name="object"></param> + void Inject(Type pluginType, object @object); /// <summary> /// Injects the given object into a Container by name for the designated Modified: trunk/Source/StructureMap/PipelineGraph.cs =================================================================== --- trunk/Source/StructureMap/PipelineGraph.cs 2009-06-03 16:21:03 UTC (rev 247) +++ trunk/Source/StructureMap/PipelineGraph.cs 2009-06-03 17:47:44 UTC (rev 248) @@ -179,11 +179,13 @@ ForType(typeof (T)).AddInstance(instance); } - public void Inject<PLUGINTYPE>(PLUGINTYPE instance) + public Instance Inject<PLUGINTYPE>(PLUGINTYPE instance) { var literalInstance = new LiteralInstance(instance); ForType(typeof (PLUGINTYPE)).AddInstance(literalInstance); SetDefault(typeof (PLUGINTYPE), literalInstance); + + return literalInstance; } public void EjectAllInstancesOf<T>() Added: trunk/Source/StructureMap.Testing/Pipeline/ContainerDisposalTester.cs =================================================================== --- trunk/Source/StructureMap.Testing/Pipeline/ContainerDisposalTester.cs (rev 0) +++ trunk/Source/StructureMap.Testing/Pipeline/ContainerDisposalTester.cs 2009-06-03 17:47:44 UTC (rev 248) @@ -0,0 +1,151 @@ +using System; +using NUnit.Framework; +using StructureMap.Configuration.DSL; + +namespace StructureMap.Testing.Pipeline +{ + [TestFixture] + public class ContainerDisposalTester + { + [SetUp] + public void SetUp() + { + } + + [Test] + public void disposing_a_nested_container_should_dispose_all_of_the_transient_objects_created_by_the_nested_container() + { + var container = new Container(x => + { + x.For<I1>().Use<C1Yes>(); + x.For<I2>().Use<C2Yes>(); + x.For<I3>().AddInstances(o => + { + o.OfConcreteType<C3Yes>().WithName("1"); + o.OfConcreteType<C3Yes>().WithName("2"); + }); + }); + + var child = container.GetNestedContainer(); + + var disposables = new Disposable[] + { + child.GetInstance<I1>().ShouldBeOfType<Disposable>(), + child.GetInstance<I2>().ShouldBeOfType<Disposable>(), + child.GetInstance<I3>("1").ShouldBeOfType<Disposable>(), + child.GetInstance<I3>("2").ShouldBeOfType<Disposable>(), + }; + + child.Dispose(); + + foreach (var disposable in disposables) + { + disposable.WasDisposed.ShouldBeTrue(); + } + } + + [Test] + public void disposing_a_nested_container_does_not_try_to_dispose_objects_created_by_the_parent() + { + var container = new Container(x => + { + x.ForSingletonOf<I1>().Use<C1No>(); + }); + + var child = container.GetNestedContainer(); + + // Blows up if the Dispose() is called + var notDisposable = child.GetInstance<I1>(); + + child.Dispose(); + } + + [Test] + public void should_dispose_objects_injected_into_the_container_1() + { + var container = new Container().GetNestedContainer(); + + var disposable = new C1Yes(); + container.Inject<I1>(disposable); + + container.GetInstance<I1>().ShouldBeTheSameAs(disposable); + + container.Dispose(); + + disposable.WasDisposed.ShouldBeTrue(); + } + + [Test] + public void should_dispose_objects_injected_into_the_container_2() + { + var container = new Container().GetNestedContainer(); + + var disposable = new C1Yes(); + container.Inject<I1>(disposable); + + container.Dispose(); + + disposable.WasDisposed.ShouldBeTrue(); + } + + [Test] + public void should_dispose_objects_injected_into_the_container_3() + { + var container = new Container().GetNestedContainer(); + + var disposable = new C1Yes(); + container.Inject<I1>("blue", disposable); + + container.Dispose(); + + disposable.WasDisposed.ShouldBeTrue(); + } + + + [Test] + public void should_dispose_objects_injected_into_the_container_4() + { + var container = new Container().GetNestedContainer(); + + var disposable = new C1Yes(); + container.Inject(typeof(I1), disposable); + + container.Dispose(); + + disposable.WasDisposed.ShouldBeTrue(); + } + } + + public class Disposable : IDisposable + { + private bool _wasDisposed; + + public void Dispose() + { + if (_wasDisposed) Assert.Fail("This object should not be disposed twice"); + + _wasDisposed = true; + } + + public bool WasDisposed { get { return _wasDisposed; } } + } + + public class NotDisposable : IDisposable + { + public void Dispose() + { + Assert.Fail("This object should not be disposed"); + } + } + + public interface I1{} + public interface I2{} + public interface I3{} + + public class C1Yes : Disposable, I1{} + public class C1No : NotDisposable, I1{} + public class C2Yes : Disposable, I2{} + public class C2No : Disposable, I2{} + public class C3Yes : Disposable, I3{} + public class C3No : Disposable, I3{} +} \ No newline at end of file Modified: trunk/Source/StructureMap.Testing/Pipeline/NestedContainerSupportTester.cs =================================================================== --- trunk/Source/StructureMap.Testing/Pipeline/NestedContainerSupportTester.cs 2009-06-03 16:21:03 UTC (rev 247) +++ trunk/Source/StructureMap.Testing/Pipeline/NestedContainerSupportTester.cs 2009-06-03 17:47:44 UTC (rev 248) @@ -14,6 +14,7 @@ { } + [Test] public void transient_service_in_the_parent_container_is_effectively_a_singleton_for_the_nested_container() { @@ -36,6 +37,29 @@ } [Test] + public void inject_into_the_child_does_not_affect_the_parent_container() + { + var parent = new Container(x => + { + x.For<IWidget>().Use<AWidget>(); + }); + + var child = parent.GetNestedContainer(); + var childWidget = new ColorWidget("blue"); + child.Inject<IWidget>(childWidget); + + // do the check repeatedly + child.GetInstance<IWidget>().ShouldBeTheSameAs(childWidget); + child.GetInstance<IWidget>().ShouldBeTheSameAs(childWidget); + child.GetInstance<IWidget>().ShouldBeTheSameAs(childWidget); + + + // now, compare to the parent + parent.GetInstance<IWidget>().ShouldNotBeTheSameAs(childWidget); + + } + + [Test] public void singleton_service_in_the_parent_is_found_by_the_child() { var parent = new Container(x => Modified: trunk/Source/StructureMap.Testing/StructureMap.Testing.csproj =================================================================== --- trunk/Source/StructureMap.Testing/StructureMap.Testing.csproj 2009-06-03 16:21:03 UTC (rev 247) +++ trunk/Source/StructureMap.Testing/StructureMap.Testing.csproj 2009-06-03 17:47:44 UTC (rev 248) @@ -346,6 +346,7 @@ <Compile Include="Pipeline\ConditionalInstanceTester.cs" /> <Compile Include="Pipeline\ConfiguredInstanceTester.cs" /> <Compile Include="Pipeline\ConstructorInstanceTester.cs" /> + <Compile Include="Pipeline\ContainerDisposalTester.cs" /> <Compile Include="Pipeline\ContainerIsInTheContainerTester.cs" /> <Compile Include="Pipeline\DefaultInstanceTester.cs" /> <Compile Include="Pipeline\GenericsHelperExpressionTester.cs" /> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |