# HG changeset patch # User Steven Robbins # Date 1295247751 0 # Node ID 9569cf22edf5be9380102435107ed7c6694c451f # Parent aafb438ec863d4bfbd4745dc7041a1ea5033895f Refactored ASP.Net support into a separate file - no need now for defines for monotouch. ASP.Net lifetime support is now an extension method inside TinyIoCAspNetExtensions.cs diff -r aafb438ec863d4bfbd4745dc7041a1ea5033895f -r 9569cf22edf5be9380102435107ed7c6694c451f platformtests/ASPNet/MvcTestApplication/MvcTestApplication/Global.asax.cs --- a/platformtests/ASPNet/MvcTestApplication/MvcTestApplication/Global.asax.cs Sat Jan 15 13:58:23 2011 +0000 +++ b/platformtests/ASPNet/MvcTestApplication/MvcTestApplication/Global.asax.cs Mon Jan 17 07:02:31 2011 +0000 @@ -4,6 +4,7 @@ using System.Web; using System.Web.Mvc; using System.Web.Routing; +using TinyIoC; namespace MvcTestApplication { diff -r aafb438ec863d4bfbd4745dc7041a1ea5033895f -r 9569cf22edf5be9380102435107ed7c6694c451f platformtests/ASPNet/MvcTestApplication/MvcTestApplication/MvcTestApplication.csproj --- a/platformtests/ASPNet/MvcTestApplication/MvcTestApplication/MvcTestApplication.csproj Sat Jan 15 13:58:23 2011 +0000 +++ b/platformtests/ASPNet/MvcTestApplication/MvcTestApplication/MvcTestApplication.csproj Mon Jan 17 07:02:31 2011 +0000 @@ -68,6 +68,9 @@ TinyIoC\TinyIoC.cs + + TinyIoC\TinyIoCAspNetExtensions.cs + diff -r aafb438ec863d4bfbd4745dc7041a1ea5033895f -r 9569cf22edf5be9380102435107ed7c6694c451f src/TinyIoC.Tests/Fakes/FakeLifetimeProvider.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/TinyIoC.Tests/Fakes/FakeLifetimeProvider.cs Mon Jan 17 07:02:31 2011 +0000 @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace TinyIoC.Tests.Fakes +{ + public class FakeLifetimeProvider : TinyIoC.TinyIoCContainer.ITinyIoCObjectLifetimeProvider + { + public object TheObject { get; set; } + + public object GetObject() + { + return TheObject; + } + + public void SetObject(object value) + { + TheObject = value; + } + + public void ReleaseObject() + { + TheObject = null; + } + } +} diff -r aafb438ec863d4bfbd4745dc7041a1ea5033895f -r 9569cf22edf5be9380102435107ed7c6694c451f src/TinyIoC.Tests/TinyIoC.Tests.csproj --- a/src/TinyIoC.Tests/TinyIoC.Tests.csproj Sat Jan 15 13:58:23 2011 +0000 +++ b/src/TinyIoC.Tests/TinyIoC.Tests.csproj Mon Jan 17 07:02:31 2011 +0000 @@ -63,6 +63,7 @@ + diff -r aafb438ec863d4bfbd4745dc7041a1ea5033895f -r 9569cf22edf5be9380102435107ed7c6694c451f src/TinyIoC.Tests/TinyIoCTests.cs --- a/src/TinyIoC.Tests/TinyIoCTests.cs Sat Jan 15 13:58:23 2011 +0000 +++ b/src/TinyIoC.Tests/TinyIoCTests.cs Mon Jan 17 07:02:31 2011 +0000 @@ -1718,7 +1718,7 @@ container.Register(); var input = new TestClassPropertyDependencies(); - container.BuildUp(input, new TinyIoC.ResolveOptions()); + container.BuildUp(input, new ResolveOptions()); Assert.IsNotNull(input.Property1); Assert.IsNotNull(input.Property2); @@ -1733,7 +1733,7 @@ container.Register(); var input = new TestClassPropertyDependencies(); - container.BuildUp(input, new TinyIoC.ResolveOptions() { UnregisteredResolutionAction = UnregisteredResolutionActions.Fail }); + container.BuildUp(input, new ResolveOptions() { UnregisteredResolutionAction = UnregisteredResolutionActions.Fail }); Assert.IsNotNull(input.Property1); Assert.IsNotNull(input.Property2); @@ -2046,7 +2046,7 @@ container.Register(); ITestInterface output; - var result = container.TryResolve(new TinyIoC.ResolveOptions(), out output); + var result = container.TryResolve(new ResolveOptions(), out output); Assert.IsTrue(result); } @@ -2058,7 +2058,7 @@ container.Register(); ITestInterface output; - var result = container.TryResolve(new TinyIoC.ResolveOptions(), out output); + var result = container.TryResolve(new ResolveOptions(), out output); Assert.IsInstanceOfType(output, typeof(ITestInterface)); } @@ -2069,7 +2069,7 @@ var container = UtilityMethods.GetContainer(); ITestInterface output; - var result = container.TryResolve(new TinyIoC.ResolveOptions(), out output); + var result = container.TryResolve(new ResolveOptions(), out output); Assert.IsFalse(result); } @@ -2116,7 +2116,7 @@ container.Register("Testing"); ITestInterface output; - var result = container.TryResolve("Testing", new TinyIoC.ResolveOptions(), out output); + var result = container.TryResolve("Testing", new ResolveOptions(), out output); Assert.IsTrue(result); } @@ -2128,7 +2128,7 @@ container.Register("Testing"); ITestInterface output; - container.TryResolve("Testing", new TinyIoC.ResolveOptions(), out output); + container.TryResolve("Testing", new ResolveOptions(), out output); Assert.IsInstanceOfType(output, typeof(ITestInterface)); } @@ -2139,7 +2139,7 @@ var container = UtilityMethods.GetContainer(); ITestInterface output; - var result = container.TryResolve("Testing", new TinyIoC.ResolveOptions(), out output); + var result = container.TryResolve("Testing", new ResolveOptions(), out output); Assert.IsFalse(result); } @@ -2221,7 +2221,7 @@ container.Register(); TestClassWithParameters output; - var result = container.TryResolve(new NamedParameterOverloads() { { "stringProperty", "test" }, { "intProperty", 2 } }, new TinyIoC.ResolveOptions(), out output); + var result = container.TryResolve(new NamedParameterOverloads() { { "stringProperty", "test" }, { "intProperty", 2 } }, new ResolveOptions(), out output); Assert.IsTrue(result); } @@ -2233,7 +2233,7 @@ container.Register(); TestClassWithParameters output; - var result = container.TryResolve(new NamedParameterOverloads() { { "stringProperty", "test" }, { "intProperty", 2 } }, new TinyIoC.ResolveOptions(), out output); + var result = container.TryResolve(new NamedParameterOverloads() { { "stringProperty", "test" }, { "intProperty", 2 } }, new ResolveOptions(), out output); Assert.IsInstanceOfType(output, typeof(TestClassWithParameters)); } @@ -2244,7 +2244,7 @@ var container = UtilityMethods.GetContainer(); TestClassWithParameters output; - var result = container.TryResolve(new NamedParameterOverloads() { { "intProperty", 2 } }, new TinyIoC.ResolveOptions(), out output); + var result = container.TryResolve(new NamedParameterOverloads() { { "intProperty", 2 } }, new ResolveOptions(), out output); Assert.IsFalse(result); } @@ -2256,7 +2256,7 @@ container.Register("Testing"); TestClassWithParameters output; - var result = container.TryResolve("Testing", new NamedParameterOverloads() { { "stringProperty", "test" }, { "intProperty", 2 } }, new TinyIoC.ResolveOptions(), out output); + var result = container.TryResolve("Testing", new NamedParameterOverloads() { { "stringProperty", "test" }, { "intProperty", 2 } }, new ResolveOptions(), out output); Assert.IsTrue(result); } @@ -2268,7 +2268,7 @@ container.Register("Testing"); TestClassWithParameters output; - var result = container.TryResolve("Testing", new NamedParameterOverloads() { { "stringProperty", "test" }, { "intProperty", 2 } }, new TinyIoC.ResolveOptions(), out output); + var result = container.TryResolve("Testing", new NamedParameterOverloads() { { "stringProperty", "test" }, { "intProperty", 2 } }, new ResolveOptions(), out output); Assert.IsInstanceOfType(output, typeof(TestClassWithParameters)); } @@ -2279,7 +2279,7 @@ var container = UtilityMethods.GetContainer(); TestClassWithParameters output; - var result = container.TryResolve("Testing", new NamedParameterOverloads() { { "intProperty", 2 } }, new TinyIoC.ResolveOptions(), out output); + var result = container.TryResolve("Testing", new NamedParameterOverloads() { { "intProperty", 2 } }, new ResolveOptions(), out output); Assert.IsFalse(result); } @@ -2400,7 +2400,7 @@ container.Register(); object output; - var result = container.TryResolve(typeof(ITestInterface), new TinyIoC.ResolveOptions(), out output); + var result = container.TryResolve(typeof(ITestInterface), new ResolveOptions(), out output); Assert.IsTrue(result); } @@ -2412,7 +2412,7 @@ container.Register(); object output; - var result = container.TryResolve(typeof(ITestInterface), new TinyIoC.ResolveOptions(), out output); + var result = container.TryResolve(typeof(ITestInterface), new ResolveOptions(), out output); Assert.IsInstanceOfType(output, typeof(ITestInterface)); } @@ -2423,7 +2423,7 @@ var container = UtilityMethods.GetContainer(); object output; - var result = container.TryResolve(typeof(ITestInterface), new TinyIoC.ResolveOptions(), out output); + var result = container.TryResolve(typeof(ITestInterface), new ResolveOptions(), out output); Assert.IsFalse(result); } @@ -2470,7 +2470,7 @@ container.Register("Testing"); object output; - var result = container.TryResolve(typeof(ITestInterface), "Testing", new TinyIoC.ResolveOptions(), out output); + var result = container.TryResolve(typeof(ITestInterface), "Testing", new ResolveOptions(), out output); Assert.IsTrue(result); } @@ -2482,7 +2482,7 @@ container.Register("Testing"); object output; - container.TryResolve(typeof(ITestInterface), "Testing", new TinyIoC.ResolveOptions(), out output); + container.TryResolve(typeof(ITestInterface), "Testing", new ResolveOptions(), out output); Assert.IsInstanceOfType(output, typeof(ITestInterface)); } @@ -2493,7 +2493,7 @@ var container = UtilityMethods.GetContainer(); object output; - var result = container.TryResolve(typeof(ITestInterface), "Testing", new TinyIoC.ResolveOptions(), out output); + var result = container.TryResolve(typeof(ITestInterface), "Testing", new ResolveOptions(), out output); Assert.IsFalse(result); } @@ -2575,7 +2575,7 @@ container.Register(); object output; - var result = container.TryResolve(typeof(TestClassWithParameters), new NamedParameterOverloads() { { "stringProperty", "test" }, { "intProperty", 2 } }, new TinyIoC.ResolveOptions(), out output); + var result = container.TryResolve(typeof(TestClassWithParameters), new NamedParameterOverloads() { { "stringProperty", "test" }, { "intProperty", 2 } }, new ResolveOptions(), out output); Assert.IsTrue(result); } @@ -2587,7 +2587,7 @@ container.Register(); object output; - var result = container.TryResolve(typeof(TestClassWithParameters), new NamedParameterOverloads() { { "stringProperty", "test" }, { "intProperty", 2 } }, new TinyIoC.ResolveOptions(), out output); + var result = container.TryResolve(typeof(TestClassWithParameters), new NamedParameterOverloads() { { "stringProperty", "test" }, { "intProperty", 2 } }, new ResolveOptions(), out output); Assert.IsInstanceOfType(output, typeof(TestClassWithParameters)); } @@ -2598,7 +2598,7 @@ var container = UtilityMethods.GetContainer(); object output; - var result = container.TryResolve(typeof(TestClassWithParameters), new NamedParameterOverloads() { { "intProperty", 2 } }, new TinyIoC.ResolveOptions(), out output); + var result = container.TryResolve(typeof(TestClassWithParameters), new NamedParameterOverloads() { { "intProperty", 2 } }, new ResolveOptions(), out output); Assert.IsFalse(result); } @@ -2610,7 +2610,7 @@ container.Register("Testing"); object output; - var result = container.TryResolve(typeof(TestClassWithParameters), "Testing", new NamedParameterOverloads() { { "stringProperty", "test" }, { "intProperty", 2 } }, new TinyIoC.ResolveOptions(), out output); + var result = container.TryResolve(typeof(TestClassWithParameters), "Testing", new NamedParameterOverloads() { { "stringProperty", "test" }, { "intProperty", 2 } }, new ResolveOptions(), out output); Assert.IsTrue(result); } @@ -2622,7 +2622,7 @@ container.Register("Testing"); object output; - var result = container.TryResolve(typeof(TestClassWithParameters), "Testing", new NamedParameterOverloads() { { "stringProperty", "test" }, { "intProperty", 2 } }, new TinyIoC.ResolveOptions(), out output); + var result = container.TryResolve(typeof(TestClassWithParameters), "Testing", new NamedParameterOverloads() { { "stringProperty", "test" }, { "intProperty", 2 } }, new ResolveOptions(), out output); Assert.IsInstanceOfType(output, typeof(TestClassWithParameters)); } @@ -2633,7 +2633,7 @@ var container = UtilityMethods.GetContainer(); object output; - var result = container.TryResolve(typeof(TestClassWithParameters), "Testing", new NamedParameterOverloads() { { "intProperty", 2 } }, new TinyIoC.ResolveOptions(), out output); + var result = container.TryResolve(typeof(TestClassWithParameters), "Testing", new NamedParameterOverloads() { { "intProperty", 2 } }, new ResolveOptions(), out output); Assert.IsFalse(result); } @@ -2793,7 +2793,7 @@ var result = container.RegisterMultiple(new Type[] { typeof(TestClassDefaultCtor), typeof(DisposableTestClassWithInterface) }); - Assert.IsInstanceOfType(result, typeof(TinyIoC.TinyIoCContainer.MultiRegisterOptions)); + Assert.IsInstanceOfType(result, typeof(TinyIoCContainer.MultiRegisterOptions)); } [TestMethod] @@ -3063,5 +3063,132 @@ Assert.IsTrue(object.ReferenceEquals(item2.Dependency, childInstance), "item2 has wrong dependency"); } + [TestMethod] + public void ToCustomLifetimeProvider_NullInstance_Throws() + { + var container = UtilityMethods.GetContainer(); + + try + { + TinyIoCContainer.RegisterOptions.ToCustomLifetimeManager(null, null, ""); + + Assert.Fail("Exception not thrown"); + } + catch (ArgumentNullException) + { + + } + } + + [TestMethod] + public void ToCustomLifetimeProvider_NullProvider_Throws() + { + var container = UtilityMethods.GetContainer(); + var registration = container.Register(); + + try + { + TinyIoCContainer.RegisterOptions.ToCustomLifetimeManager(registration, null, ""); + + Assert.Fail("Exception not thrown"); + } + catch (ArgumentNullException) + { + + } + } + + [TestMethod] + public void ToCustomLifetimeProvider_NullErrorString_Throws() + { + var container = UtilityMethods.GetContainer(); + var registration = container.Register(); + + try + { + TinyIoCContainer.RegisterOptions.ToCustomLifetimeManager(registration, new Fakes.FakeLifetimeProvider(), null); + + Assert.Fail("Exception not thrown"); + } + catch (ArgumentException) + { + + } + } + + [TestMethod] + public void ToCustomLifetimeProvider_EmptyErrorString_Throws() + { + var container = UtilityMethods.GetContainer(); + var registration = container.Register(); + + try + { + TinyIoCContainer.RegisterOptions.ToCustomLifetimeManager(registration, new Fakes.FakeLifetimeProvider(), ""); + + Assert.Fail("Exception not thrown"); + } + catch (ArgumentException) + { + + } + } + + [TestMethod] + public void CustomLifetimeProvider_WhenResolved_CallsGetObjectOnLifetimeProvider() + { + var container = UtilityMethods.GetContainer(); + var providerMock = new Mock(); + providerMock.Setup(p => p.GetObject()).Returns(new TestClassDefaultCtor()); + var registration = container.Register(); + TinyIoCContainer.RegisterOptions.ToCustomLifetimeManager(registration, providerMock.Object, "Mock"); + + container.Resolve(); + + providerMock.Verify(p => p.GetObject(), Times.Once(), "not called"); + } + + [TestMethod] + public void CustomLifetimeProvider_GetObjectReturnsNull_CallsSetObjectOnProvider() + { + var container = UtilityMethods.GetContainer(); + var providerMock = new Mock(); + providerMock.Setup(p => p.GetObject()).Returns(null); + providerMock.Setup(p => p.SetObject(It.IsAny())).Verifiable(); + var registration = container.Register(); + TinyIoCContainer.RegisterOptions.ToCustomLifetimeManager(registration, providerMock.Object, "Mock"); + + container.Resolve(); + + providerMock.Verify(p => p.SetObject(It.IsAny()), Times.Once(), "not called"); + } + + [TestMethod] + public void CustomLifetimeProvider_SwitchingToAnotherFactory_CallsReleaseObjectOnProvider() + { + var container = UtilityMethods.GetContainer(); + var providerMock = new Mock(); + providerMock.Setup(p => p.ReleaseObject()).Verifiable(); + var registration = container.Register(); + registration = TinyIoCContainer.RegisterOptions.ToCustomLifetimeManager(registration, providerMock.Object, "Mock"); + + registration.AsSingleton(); + + providerMock.Verify(p => p.ReleaseObject(), Times.AtLeastOnce(), "not called"); + } + + [TestMethod] + public void CustomLifetimeProvider_ContainerDisposed_CallsReleaseObjectOnProvider() + { + var container = UtilityMethods.GetContainer(); + var providerMock = new Mock(); + providerMock.Setup(p => p.ReleaseObject()).Verifiable(); + var registration = container.Register(); + TinyIoCContainer.RegisterOptions.ToCustomLifetimeManager(registration, providerMock.Object, "Mock"); + + container.Dispose(); + + providerMock.Verify(p => p.ReleaseObject(), Times.AtLeastOnce(), "not called"); + } } } diff -r aafb438ec863d4bfbd4745dc7041a1ea5033895f -r 9569cf22edf5be9380102435107ed7c6694c451f src/TinyIoC/TinyIoC.cs --- a/src/TinyIoC/TinyIoC.cs Sat Jan 15 13:58:23 2011 +0000 +++ b/src/TinyIoC/TinyIoC.cs Mon Jan 17 07:02:31 2011 +0000 @@ -13,11 +13,6 @@ // FITNESS FOR A PARTICULAR PURPOSE. //=============================================================================== -// -- MONOTOUCH IMPORTANT -- // -// If you are intending to use MonoTouch you *must* define MONOTOUCH or the code -// will not compile. -// -- MONOTOUCH IMPORTANT -- // - #region Preprocessor Directives // Uncomment this line if you want the container to automatically // register the TinyMessenger messenger/event aggregator @@ -30,7 +25,6 @@ #define APPDOMAIN_GETASSEMBLIES // Platform supports getting all assemblies from the AppDomain object #define UNBOUND_GENERICS_GETCONSTRUCTORS // Platform supports GetConstructors on unbound generic types #define GETPARAMETERS_OPEN_GENERICS // Platform supports GetParameters on open generics -#define ASPNET // Adds ASP.Net pre-request singleton support // CompactFramework / Windows Phone 7 // By default does not support System.Linq.Expressions. @@ -39,7 +33,6 @@ #undef EXPRESSIONS #undef APPDOMAIN_GETASSEMBLIES #undef UNBOUND_GENERICS_GETCONSTRUCTORS -#undef ASPNET #endif // PocketPC has a bizarre limitation on enumerating parameters on unbound generic methods. @@ -50,12 +43,8 @@ #if SILVERLIGHT #undef APPDOMAIN_GETASSEMBLIES -#undef ASPNET #endif -#if MONOTOUCH -#undef ASPNET -#endif #endregion namespace TinyIoC { @@ -66,9 +55,6 @@ #if EXPRESSIONS using System.Linq.Expressions; #endif -#if ASPNET - using System.Web; -#endif #region SafeDictionary public class SafeDictionary : IDisposable @@ -480,18 +466,6 @@ return _Container.AddUpdateRegistration(_Registration, currentFactory.SingletonVariant); } -#if ASPNET - public RegisterOptions AsPerRequestSingleton() - { - var currentFactory = _Container.GetCurrentFactory(_Registration); - - if (currentFactory == null) - throw new TinyIoCRegistrationException(_Registration.Type, "singleton"); - - return _Container.AddUpdateRegistration(_Registration, currentFactory.PerRequestSingletonVariant); - } -#endif - /// /// Make registration multi-instance if possible /// @@ -561,6 +535,33 @@ return this; } #endif + /// + /// Switches to a custom lifetime manager factory if possible. + /// + /// Usually used for RegisterOptions "To*" extension methods such as the ASP.Net per-request one. + /// + /// RegisterOptions instance + /// Custom lifetime manager + /// Error string to display if switch fails + /// RegisterOptions + public static RegisterOptions ToCustomLifetimeManager(RegisterOptions instance, ITinyIoCObjectLifetimeProvider lifetimeProvider, string errorString) + { + if (instance == null) + throw new ArgumentNullException("instance", "instance is null."); + + if (lifetimeProvider == null) + throw new ArgumentNullException("lifetimeProvider", "lifetimeProvider is null."); + + if (String.IsNullOrEmpty(errorString)) + throw new ArgumentException("errorString is null or empty.", "errorString"); + + var currentFactory = instance._Container.GetCurrentFactory(instance._Registration); + + if (currentFactory == null) + throw new TinyIoCRegistrationException(instance._Registration.Type, errorString); + + return instance._Container.AddUpdateRegistration(instance._Registration, currentFactory.GetCustomObjectLifetimeVariant(lifetimeProvider, errorString)); + } } /// @@ -1870,6 +1871,29 @@ #endregion #region Object Factories + /// + /// Provides custom lifetime management for ASP.Net per-request lifetimes etc. + /// + public interface ITinyIoCObjectLifetimeProvider + { + /// + /// Gets the stored object if it exists, or null if not + /// + /// Object instance or null + object GetObject(); + + /// + /// Store the object + /// + /// Object to store + void SetObject(object value); + + /// + /// Release the object + /// + void ReleaseObject(); + } + private abstract class ObjectFactoryBase { /// @@ -1905,15 +1929,7 @@ throw new TinyIoCRegistrationException(this.GetType(), "singleton"); } } -#if ASPNET - public virtual TinyIoCContainer.ObjectFactoryBase PerRequestSingletonVariant - { - get - { - throw new TinyIoCRegistrationException(this.GetType(), "per-request-singleton"); - } - } -#endif + public virtual ObjectFactoryBase MultiInstanceVariant { get @@ -1938,6 +1954,11 @@ } } + public virtual ObjectFactoryBase GetCustomObjectLifetimeVariant(ITinyIoCObjectLifetimeProvider lifetimeProvider, string errorString) + { + throw new TinyIoCRegistrationException(this.GetType(), errorString); + } + public virtual void SetConstructor(ConstructorInfo constructor) { Constructor = constructor; @@ -1986,15 +2007,11 @@ } } -#if ASPNET - public override ObjectFactoryBase PerRequestSingletonVariant + public override ObjectFactoryBase GetCustomObjectLifetimeVariant(ITinyIoCObjectLifetimeProvider lifetimeProvider, string errorString) { - get - { - return new PerRequestSingletonFactory(); - } + return new CustomObjectLifetimeFactory(lifetimeProvider, errorString); } -#endif + public override ObjectFactoryBase MultiInstanceVariant { get @@ -2311,15 +2328,10 @@ } } -#if ASPNET - public override ObjectFactoryBase PerRequestSingletonVariant + public override ObjectFactoryBase GetCustomObjectLifetimeVariant(ITinyIoCObjectLifetimeProvider lifetimeProvider, string errorString) { - get - { - return new PerRequestSingletonFactory(); - } + return new CustomObjectLifetimeFactory(lifetimeProvider, errorString); } -#endif public override ObjectFactoryBase MultiInstanceVariant { @@ -2350,23 +2362,27 @@ } } -#if ASPNET /// - /// A factory that lazy instantiates a type and always returns the same instance + /// A factory that offloads lifetime to an external lifetime provider /// /// Registered type /// Type to instantiate - private class PerRequestSingletonFactory : ObjectFactoryBase, IDisposable + private class CustomObjectLifetimeFactory : ObjectFactoryBase, IDisposable where RegisterType : class where RegisterImplementation : class, RegisterType { - private readonly string _KeyName = String.Format("TinyIoC.{0}.{1}", typeof(RegisterType).FullName, Guid.NewGuid()); private readonly object SingletonLock = new object(); - - public PerRequestSingletonFactory() + private readonly ITinyIoCObjectLifetimeProvider _LifetimeProvider; + + public CustomObjectLifetimeFactory(ITinyIoCObjectLifetimeProvider lifetimeProvider, string errorMessage) { + if (lifetimeProvider == null) + throw new ArgumentNullException("lifetimeProvider", "lifetimeProvider is null."); + if (typeof(RegisterImplementation).IsAbstract || typeof(RegisterImplementation).IsInterface) - throw new TinyIoCRegistrationTypeException(typeof(RegisterImplementation), "SingletonFactory"); + throw new TinyIoCRegistrationTypeException(typeof(RegisterImplementation), errorMessage); + + _LifetimeProvider = lifetimeProvider; } public override Type CreatesType @@ -2376,18 +2392,15 @@ public override object GetObject(TinyIoCContainer container, NamedParameterOverloads parameters, ResolveOptions options) { - if (parameters.Count != 0) - throw new ArgumentException("Cannot specify parameters for singleton types"); - RegisterImplementation current; lock (SingletonLock) { - current = HttpContext.Current.Items[_KeyName] as RegisterImplementation; + current = _LifetimeProvider.GetObject() as RegisterImplementation; if (current == null) { current = container.ConstructType(typeof(RegisterImplementation), Constructor, options) as RegisterImplementation; - HttpContext.Current.Items[_KeyName] = current; + _LifetimeProvider.SetObject(current); } } @@ -2398,26 +2411,26 @@ { get { + _LifetimeProvider.ReleaseObject(); return new SingletonFactory(); } } - public override ObjectFactoryBase PerRequestSingletonVariant - { - get - { - return this; - } - } - public override ObjectFactoryBase MultiInstanceVariant { get { + _LifetimeProvider.ReleaseObject(); return new MultiInstanceFactory(); } } + public override ObjectFactoryBase GetCustomObjectLifetimeVariant(ITinyIoCObjectLifetimeProvider lifetimeProvider, string errorString) + { + _LifetimeProvider.ReleaseObject(); + return new CustomObjectLifetimeFactory(lifetimeProvider, errorString); + } + public override ObjectFactoryBase GetFactoryForChildContainer(TinyIoCContainer parent, TinyIoCContainer child) { // We make sure that the singleton is constructed before the child container takes the factory. @@ -2429,17 +2442,9 @@ public void Dispose() { - var current = HttpContext.Current.Items[_KeyName] as RegisterImplementation; - if (current != null) - { - var disposable = current as IDisposable; - - if (disposable != null) - disposable.Dispose(); - } + _LifetimeProvider.ReleaseObject(); } } -#endif #endregion #region Singleton Container diff -r aafb438ec863d4bfbd4745dc7041a1ea5033895f -r 9569cf22edf5be9380102435107ed7c6694c451f src/TinyIoC/TinyIoC.csproj --- a/src/TinyIoC/TinyIoC.csproj Sat Jan 15 13:58:23 2011 +0000 +++ b/src/TinyIoC/TinyIoC.csproj Mon Jan 17 07:02:31 2011 +0000 @@ -69,6 +69,7 @@ + diff -r aafb438ec863d4bfbd4745dc7041a1ea5033895f -r 9569cf22edf5be9380102435107ed7c6694c451f src/TinyIoC/TinyIoCAspNetExtensions.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/TinyIoC/TinyIoCAspNetExtensions.cs Mon Jan 17 07:02:31 2011 +0000 @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Web; + +namespace TinyIoC +{ + public class HttpContextLifetimeProvider : TinyIoCContainer.ITinyIoCObjectLifetimeProvider + { + private readonly string _KeyName = String.Format("TinyIoC.HttpContext.{0}", Guid.NewGuid()); + + public object GetObject() + { + return HttpContext.Current.Items[_KeyName]; + } + + public void SetObject(object value) + { + HttpContext.Current.Items[_KeyName] = value; + } + + public void ReleaseObject() + { + var item = GetObject() as IDisposable; + + if (item != null) + item.Dispose(); + + SetObject(null); + } + } + + public static class TinyIoCAspNetExtensions + { + public static TinyIoC.TinyIoCContainer.RegisterOptions AsPerRequestSingleton(this TinyIoC.TinyIoCContainer.RegisterOptions registerOptions) + { + return TinyIoCContainer.RegisterOptions.ToCustomLifetimeManager(registerOptions, new HttpContextLifetimeProvider(), "per request singleton"); + } + } +}