Пример #1
0
        public void Dispose_WithAsyncDisposable_ThrowsException()
        {
            // Arrange
            var container = ContainerFactory.New();

            container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();

            container.Register <AsyncDisposable>(Lifestyle.Scoped);

            var scope = AsyncScopedLifestyle.BeginScope(container);

            var plugin = container.GetInstance <AsyncDisposable>();

            // Act
            Action action = () => scope.Dispose();

            // Assert
            AssertThat.ThrowsWithExceptionMessageContains <InvalidOperationException>(
                "AsyncDisposable only implements IAsyncDisposable, but not IDisposable. Make sure to call " +
                "Scope.DisposeScopeAsync() instead of Scope.Dispose().",
                action);
        }
Пример #2
0
        public async Task DisposeScopeAsync_WithSyncAndAsyncDisposableScopedInstanceDelegateRegistration_DisposesThatInstanceOnlyAsynchronously()
        {
            // Arrange
            var container = ContainerFactory.New();

            container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();

            container.Register <IFoo>(() => new SyncAsyncDisposable(), Lifestyle.Scoped);

            var scope = AsyncScopedLifestyle.BeginScope(container);

            var plugin = container.GetInstance <IFoo>() as SyncAsyncDisposable;

            // Act
            await scope.DisposeScopeAsync();

            // Assert
            Assert.IsTrue(plugin.AsyncDisposed);
            Assert.IsFalse(plugin.SyncDisposed,
                           "In case both interfaces are implemented, only DisposeAsync should be called. " +
                           "The C# compiler acts this way as well.");
        }
Пример #3
0
        public void Dispose_WithSyncAsyncDisposableScopedRegistration_DisposesThatInstance()
        {
            // Arrange
            var container = ContainerFactory.New();

            container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();

            container.Register <SyncAsyncDisposable>(Lifestyle.Scoped);

            var scope = AsyncScopedLifestyle.BeginScope(container);

            var plugin = container.GetInstance <SyncAsyncDisposable>();

            // Act
            // Because SyncAsyncDisposable implements IDisposable, the sync dispose call should succeed.
            scope.Dispose();

            // Assert
            Assert.IsTrue(plugin.SyncDisposed);
            Assert.IsFalse(plugin.AsyncDisposed,
                           "DisposeAsync was called, but this involves blocking which could cause a deadlock. A no-no.");
        }
        public void GetAllInstances_OnUnregisteredType_TriggersUnregisteredTypeResolution()
        {
            // Arrange
            bool resolveUnregisteredTypeWasTriggered = false;

            var container = ContainerFactory.New();

            container.ResolveUnregisteredType += (s, e) =>
            {
                if (e.UnregisteredServiceType == typeof(IEnumerable <Exception>))
                {
                    resolveUnregisteredTypeWasTriggered = true;
                }
            };

            // Act
            Action action = () => container.GetAllInstances <Exception>();

            // Assert
            AssertThat.Throws <ActivationException>(action);
            Assert.IsTrue(resolveUnregisteredTypeWasTriggered);
        }
        public void GetInstance_OnUnregisteredCollection_TriggersUnregisteredTypeResolution()
        {
            // Arrange
            bool resolveUnregisteredTypeWasTriggered = false;

            var container = ContainerFactory.New();

            container.ResolveUnregisteredType += (s, e) =>
            {
                if (e.UnregisteredServiceType == typeof(IEnumerable <Exception>))
                {
                    resolveUnregisteredTypeWasTriggered = true;
                    e.Register(() => Enumerable.Empty <Exception>());
                }
            };

            // Act
            container.GetInstance <IEnumerable <Exception> >();

            // Assert
            Assert.IsTrue(resolveUnregisteredTypeWasTriggered);
        }
Пример #6
0
        public void GetInstance_RequestingOnRootTypeDependingIndirectlyOnItselfThroughDelegateRegistration_Throws()
        {
            // Arrange
            var container = ContainerFactory.New();

            container.Register <ComponentDependingOn <IOne> >();
            container.Register <IOne>(() => new One(container.GetInstance <ITwo>()));
            container.Register <ITwo>(() => new Two(container.GetInstance <IOne>()));

            try
            {
                // Act
                container.GetInstance <ComponentDependingOn <IOne> >();

                // Assert
                Assert.Fail("An exception was expected, because A depends indirectly on itself.");
            }
            catch (ActivationException)
            {
                // This exception is expected.
            }
        }
        public void GetInstance_EventRegisteredForNonRootTypeThatThrowsException_ThrowsAnDescriptiveException()
        {
            // Arrange
            var container = ContainerFactory.New();

            container.Register <UserServiceBase, RealUserService>();

            container.ResolveUnregisteredType += (s, e) =>
            {
                e.Register(() => { throw new Exception(); });
            };

            // Act
            Action action = () => container.GetInstance <UserServiceBase>();

            // Assert
            AssertThat.ThrowsWithExceptionMessageContains <Exception>(
                "The delegate that was registered for service type IUserRepository using the " +
                "UnregisteredTypeEventArgs.Register(Func<object>) method threw an exception",
                action,
                "Exception message was not descriptive.");
        }
Пример #8
0
        public void GetInstance_RequestingSingletonTypeDependingIndirectlyOnItselfViaSingletonType_Throws()
        {
            // Arrange
            var container = ContainerFactory.New();

            // Note: A depends on B which depends on A.
            container.Register <A>(Lifestyle.Singleton);
            container.Register <B>(Lifestyle.Singleton);

            try
            {
                // Act
                container.GetInstance <A>();

                // Assert
                Assert.Fail("An exception was expected, because A depends indirectly on itself.");
            }
            catch (ActivationException)
            {
                // This exception is expected.
            }
        }
Пример #9
0
        public void GetInstance_RequestingSingletonTypeDependingIndirectlyOnItselfThroughInterfaces_Throws()
        {
            // Arrange
            var container = ContainerFactory.New();

            // One depends on ITwo and Two depends on IOne.
            container.Register <IOne, One>(Lifestyle.Singleton);
            container.Register <ITwo, Two>(Lifestyle.Singleton);

            try
            {
                // Act
                container.GetInstance <IOne>();

                // Assert
                Assert.Fail("An exception was expected, because A depends indirectly on itself.");
            }
            catch (ActivationException)
            {
                // This exception is expected.
            }
        }
        public void GetInstance_MultipleRegisteredInitializers_RunsInitializersInOrderOfRegistration()
        {
            // Arrange
            int index             = 1;
            int initializer1Index = 0;
            int initializer2Index = 0;
            int initializer3Index = 0;

            var container = ContainerFactory.New();

            container.RegisterInitializer <ICommand>(c => { initializer1Index = index++; });
            container.RegisterInitializer <ConcreteCommand>(c => { initializer3Index = index++; });
            container.RegisterInitializer <CommandBase>(c => { initializer2Index = index++; });

            // Act
            container.GetInstance <ConcreteCommand>();

            // Assert
            Assert.AreEqual(1, initializer1Index, "ICommand initializer did not run in expected order.");
            Assert.AreEqual(2, initializer3Index, "ConcreteCommand initializer did not run in expected order.");
            Assert.AreEqual(3, initializer2Index, "CommandBase initializer did not run in expected order.");
        }
Пример #11
0
        public void InitializeInstance_WithPropertyInjection_InjectsProperty()
        {
            // Arrange
            var instanceToInitialize = new ServiceWithProperty <RealTimeProvider>();

            Assert.IsNull(instanceToInitialize.Dependency, "Test setup failed.");

            var container = ContainerFactory.New();

            container.Options.PropertySelectionBehavior = new PredicatePropertySelectionBehavior
            {
                Predicate = property => property.Name == "Dependency"
            };

            var registration = container.GetRegistration(instanceToInitialize.GetType()).Registration;

            // Act
            registration.InitializeInstance(instanceToInitialize);

            // Assert
            Assert.IsNotNull(instanceToInitialize.Dependency);
        }
Пример #12
0
        public void Register_AbstractTypeWithSinglePublicConstructor_ThrowsExpectedException()
        {
            // Arrange
            string expectedMessage = @"
                The given type RegisterConcreteTests.AbstractTypeWithSinglePublicConstructor is not a concrete
                type. Please use one of the other overloads to register this type.
                ".TrimInside();

            var container = ContainerFactory.New();

            try
            {
                // Act
                container.Register<AbstractTypeWithSinglePublicConstructor>();

                Assert.Fail("The abstract type was not expected to be registered successfully.");
            }
            catch (ArgumentException ex)
            {
                AssertThat.ExceptionMessageContains(expectedMessage, ex);
            }
        }
        public void GetInstance_SubTypeRegisteredWithFuncReturningNull_ThrowsExpectedException()
        {
            // Arrange
            var container = ContainerFactory.New();

            container.Register <IUserRepository>(() => null);

            try
            {
                // Act
                container.GetInstance <RealUserService>();

                // Assert
                Assert.Fail("Exception expected.");
            }
            catch (ActivationException ex)
            {
                Assert.IsTrue(ex.Message.Contains(
                                  "The registered delegate for type IUserRepository returned null."),
                              "Actual: " + ex.Message);
            }
        }
Пример #14
0
        public void GetInstance_LambdaThatCallsBackIntoContainerExecutedFromScopeResolve_ResolvesTheInstanceAsScoped()
        {
            // Arrange
            var container = ContainerFactory.New();

            container.Options.DefaultScopedLifestyle = ScopedLifestyle.Flowing;

            // Calling back into the container to get a scoped instance, from within an instanceCreator lambda,
            // should work, in case the the root object is resolved from a scope.
            container.Register <ILogger>(() => container.GetInstance <NullLogger>());
            container.Register <NullLogger>(Lifestyle.Scoped);
            container.Register <ServiceDependingOn <ILogger> >();

            var scope = new Scope(container);

            // Act
            var s1 = scope.GetInstance <ServiceDependingOn <ILogger> >();
            var s2 = scope.GetInstance <ServiceDependingOn <ILogger> >();

            // Assert
            Assert.AreSame(s1.Dependency, s2.Dependency, "Logger was expected to be scoped.");
        }
        public void RegisterTypes_SuppliedWithOpenGenericType_FailsWithExpectedException()
        {
            // Arrange
            var container = ContainerFactory.New();

            Type[] types = new[] { typeof(GenericHandler <>) };

            // Act
            Action action = () => container.Register(typeof(IBatchCommandHandler <>), types);

            // Assert
            AssertThat.ThrowsWithParamName("implementationTypes", action);
            AssertThat.ThrowsWithExceptionMessageContains <ArgumentException>(@"
                The supplied list of types contains an open-generic type, but this method is unable to 
                handle open-generic implementations—it can only map a single implementation to
                closed-generic service types. You must register this open-generic type separately using
                the Register(Type, Type) overload. Alternatively, try using Container.Collection.Register
                instead, if you expect to have multiple implementations per closed-generic service type
                and want to inject a collection of them into consumers."
                                                                              .TrimInside(),
                                                                              action);
        }
        public void RegisterOpenGeneric_PredicateContext_ImplementationTypeIsClosedImplentation()
        {
            bool called = false;

            // Arrange
            var container = ContainerFactory.New();

            container.RegisterConditional(typeof(IOpenGenericWithPredicate <>), typeof(OpenGenericWithPredicate1 <>),
                                          Lifestyle.Transient, c =>
            {
                Assert.IsFalse(c.ImplementationType.ContainsGenericParameter(), "ImplementationType should be a closed type");

                called = true;
                return(true);
            });

            // Act
            var result = container.GetInstance <IOpenGenericWithPredicate <int> >();

            // Assert
            Assert.IsTrue(called, "Predicate was not called");
        }
        public void GetInstance_GenericConditionalRegistrationWithFallbackBehaviorRegisteredBeforeClosed_Throws()
        {
            // Arrange
            var container = ContainerFactory.New();

            // Conditional fallback before the closed registration.
            container.RegisterConditional(typeof(IGeneric <>), typeof(GenericType <>), c => !c.Handled);

            container.Register <IGeneric <int>, IntGenericType>();

            // Act
            Action action = () => container.GetInstance <IGeneric <int> >();

            // Assert
            AssertThat.ThrowsWithExceptionMessageContains <ActivationException>(
                "Multiple applicable registrations found for IGeneric<Int32>",
                action);

            AssertThat.ThrowsWithExceptionMessageContains <ActivationException>(
                "make the fallback registration last and check the Handled property in the predicate",
                action);
        }
        public void GetInstance_MultipleApplicableConditionalNonGenericRegistrations_ThrowsExpectedException()
        {
            // Arrange
            var container = ContainerFactory.New();

            container.RegisterConditional(typeof(ILogger), typeof(NullLogger), Lifestyle.Singleton, c => true);
            container.RegisterConditional(typeof(ILogger), typeof(ConsoleLogger), Lifestyle.Singleton, c => true);

            // Act
            Action action = () => container.GetInstance <ServiceWithDependency <ILogger> >();

            // Assert
            AssertThat.ThrowsWithExceptionMessageContains <ActivationException>(@"
                Multiple applicable registrations found for ILogger. The applicable registrations are
                (1) the conditional registration for ILogger using NullLogger and
                (2) the conditional registration for ILogger using ConsoleLogger.
                If your goal is to make one registration a fallback in case another registration is not
                applicable, make the fallback registration last and check the Handled property in the
                predicate."
                                                                                .TrimInside(),
                                                                                action);
        }
        public void RegisterConditionalGeneric_ForConstraintTypeAfterAnUnconditionalConstraintRegistrationForTheSameImplementationTypeHasBeenMade_ThrowsAnExpressiveException()
        {
            // Arrange
            var container = ContainerFactory.New();

            container.Register(typeof(IGeneric <>), typeof(GenericClassType <>));

            // Act
            // Although we skip checks for types with type constraints, these two registrations use the same
            // implementation type and this will always cause overlap.
            Action action = () => container.RegisterConditional(typeof(IGeneric <>), typeof(GenericClassType <>), c => true);

            // Assert
            AssertThat.ThrowsWithExceptionMessageContains <InvalidOperationException>(@"
                There is already a registration for IGeneric<T> (with implementation GenericClassType<TClass>) 
                that overlaps with the registration for GenericClassType<TClass> that you are trying to make. 
                This new registration would cause ambiguity, because both registrations would be used for the 
                same closed service types. Either remove one of the registrations or make them both 
                conditional."
                                                                                      .TrimInside(),
                                                                                      action);
        }
        public void GetInstance_DelegateReturningNullRegisteredUsingRegisterSingleByFuncOfNonRootType_ThrowsActivationExceptionWithExpectedExceptionMessage()
        {
            // Arrange
            var container = ContainerFactory.New();

            container.RegisterSingle <IUserRepository>(() => null);

            try
            {
                // Act
                container.GetInstance <RealUserService>();

                // Assert
                Assert.Fail("The GetInstance method was expected to fail, because of the faulty registration.");
            }
            catch (ActivationException ex)
            {
                string expectedMessage = "The registered delegate for type IUserRepository returned null.";

                AssertThat.ExceptionMessageContains(expectedMessage, ex);
            }
        }
Пример #21
0
        public void GetInstance_UnregisteredConcreteTypeWithInterceptor_CallsEventOnce()
        {
            // Arrange
            int expectedCallCount = 1;
            int actualCallCount   = 0;

            var container = ContainerFactory.New();

            container.ExpressionBuilt += (sender, e) =>
            {
                if (e.RegisteredServiceType == typeof(SqlUserRepository))
                {
                    actualCallCount++;
                }
            };

            // Act
            container.GetInstance <SqlUserRepository>();

            // Assert
            Assert.AreEqual(expectedCallCount, actualCallCount);
        }
Пример #22
0
        public void GetInstance_ResolvingScopedDependencyDirectlyFromScope_ResolvesTheInstanceAsScoped()
        {
            // Arrange
            var container = ContainerFactory.New();

            // We need a 'dummy' scoped lifestyle to be able to use Lifestyle.Scoped
            container.Options.DefaultScopedLifestyle = ScopedLifestyle.Flowing;

            container.Register <ILogger, NullLogger>(Lifestyle.Scoped);

            var scope1 = new Scope(container);
            var scope2 = new Scope(container);

            // Act
            var s1 = scope1.GetInstance <ServiceDependingOn <ILogger> >();
            var s2 = scope1.GetInstance <ServiceDependingOn <ILogger> >();
            var s3 = scope2.GetInstance <ServiceDependingOn <ILogger> >();

            // Assert
            Assert.AreSame(s1.Dependency, s2.Dependency, "Logger was expected to be scoped but was transient.");
            Assert.AreNotSame(s3.Dependency, s2.Dependency, "Logger was expected to be scoped but was singleton.");
        }
        public void GetInstance_CalledForDecoratedUncontrolledCollection_CallsEventForBothTheInstanceAndTheDecorator()
        {
            // Arrange
            var actualContexts = new List <InstanceInitializationData>();

            var container = ContainerFactory.New();

            // Container uncontrolled collection
            IEnumerable <ICommandHandler <RealCommand> > handlers = new ICommandHandler <RealCommand>[]
            {
                new StubCommandHandler(),
            };

            container.Collection.Register <ICommandHandler <RealCommand> >(handlers);

            container.RegisterInitializer(actualContexts.Add, TruePredicate);

            container.RegisterDecorator(typeof(ICommandHandler <>), typeof(RealCommandHandlerDecorator));

            // Act
            var producer = container.GetRegistration(typeof(IEnumerable <ICommandHandler <RealCommand> >));

            var decorator = container.GetAllInstances <ICommandHandler <RealCommand> >().Single()
                            as RealCommandHandlerDecorator;

            // Assert
            Assert.AreEqual(2, actualContexts.Count, "Two event args were expected.");

            Assert.AreSame(producer.Registration, actualContexts.First().Context.Registration);

            Assert.AreEqual(
                typeof(IEnumerable <ICommandHandler <RealCommand> >),
                actualContexts.First().Context.Registration.ImplementationType);

            Assert.AreEqual(
                typeof(RealCommandHandlerDecorator),
                actualContexts.Second().Context.Registration.ImplementationType);
        }
        public void GetInstance_ExpressionBuildingChangedExpressionInAnIncompatibleWay_ThrowsExpectedException()
        {
            // Arrange
            var container = ContainerFactory.New();

            container.Register <IUserRepository, SqlUserRepository>(Lifestyle.Singleton);

            // Act
            container.ExpressionBuilding += (s, e) =>
                                            e.Expression = Expression.Constant("some string", typeof(string));

            Action action = () => container.GetInstance(typeof(IUserRepository));

            // Assert
            AssertThat.ThrowsWithExceptionMessageContains <ActivationException>(@"
                You are trying to set the ExpressionBuildingEventArgs.Expression property with an Expression
                instance that has a type of String. The expression type however should be a
                SqlUserRepository (or a sub type). You can't change the type of the expression using the
                ExpressionBuilding event. If you need to change the implementation, please use the
                ExpressionBuilt event instead."
                                                                                .TrimInside(),
                                                                                action);
        }
        public void GetInstance_CalledSimultaneouslyToRequestTheSameType_ShouldNotTriggerTheRecursionProtection()
        {
            // Arrange
            var container = ContainerFactory.New();

            container.Register <IUserRepository>(() =>
            {
                // We wait a bit here to make sure all three threads run this method simultaneously.
                Thread.Sleep(200);
                return(new SqlUserRepository());
            });

            // Act
            var thread2 = ThreadWrapper.StartNew(() => container.GetInstance <IUserRepository>());
            var thread3 = ThreadWrapper.StartNew(() => container.GetInstance <IUserRepository>());

            // Also run on this thread.
            container.GetInstance <IUserRepository>();

            // Assert
            Assert_FinishedWithoutExceptions(thread2);
            Assert_FinishedWithoutExceptions(thread3);
        }
        public void GetRegistration_WhenTheRegistrationIsUnknownButCanBeCreatedUsingUnregTypeRes_DoesNotLockTheContainer()
        {
            // Arrange
            var container = ContainerFactory.New();

            // Not sure whether it would be wise to always lock the container when an unregistered event handler is fired.
            container.ResolveUnregisteredType += (s, e) =>
            {
                e.Register(Lifestyle.Singleton.CreateRegistration <RealTimeProvider>(container));
            };

            // Act
            var prod = container.GetRegistration(typeof(ITimeProvider));

            Assert.IsNotNull(prod, "Test setup failed.");

            // Arrange
            Assert.IsTrue(container.IsLocked, @"
            Whenever a not explicitly made registration can be returned using unregistered type resolution, 
            the container needs to be locked, changing the container might invalidate the registration. 
            For instance, adding unregistered type resolution events later, might cause a different registration to
            be returned when GetRegistration is called again.");
        }
        public void Validate_InValidRegisterSingleByFuncRegistration_ThrowsExpectedExceptionMessage()
        {
            // Arrange
            string expectedMessage = "The registered delegate for type IUserRepository returned null";

            var container = ContainerFactory.New();
            Func <IUserRepository> invalidDelegate = () => null;

            container.RegisterSingle <IUserRepository>(invalidDelegate);

            try
            {
                // Act
                container.Verify();

                // Arrange
                Assert.Fail("Exception expected.");
            }
            catch (InvalidOperationException ex)
            {
                AssertThat.StringContains(expectedMessage, ex.Message);
            }
        }
Пример #28
0
        public void Verify_ResolvingACollectionOfSingletonsBeforeAndAfterCallingVerify_ShouldStillYieldTheSameInstance()
        {
            // Arrange
            var container = ContainerFactory.New();

            container.Collection.Register(typeof(IEventHandler <>), new Type[]
            {
                typeof(StructEventHandler),
            });

            container.Collection.Append(typeof(IEventHandler <>),
                                        Lifestyle.Singleton.CreateRegistration <AuditableEventEventHandler>(container));

            var handler = container.GetAllInstances <IEventHandler <AuditableEvent> >().Single();

            container.Verify();

            // Act
            var handler2 = container.GetAllInstances <IEventHandler <AuditableEvent> >().Single();

            // Assert
            Assert.AreSame(handler, handler2);
        }
Пример #29
0
        public void Dispose_MultipleDisposableSingletons_DisposesThemInOppositeOrderOfCreation()
        {
            // Arrange
            var instances = new List <DisposableService>();

            var container = ContainerFactory.New();

            container.Register <IService, DisposableService>(Lifestyle.Singleton);
            container.Register <DisposableService>(Lifestyle.Singleton);

            var instance1 = container.GetInstance <DisposableService>();
            var instance2 = container.GetInstance <IService>() as DisposableService;

            instance1.Disposing += instances.Add;
            instance2.Disposing += instances.Add;

            // Act
            container.Dispose();

            // Assert
            Assert.AreSame(instance2, instances[0], "Instances are expected to be disposed in opposite order.");
            Assert.AreSame(instance1, instances[1], "Instances are expected to be disposed in opposite order.");
        }
        public void GetInstance_WithUnregisteredType_InvokesEvent()
        {
            // Arrange
            bool eventCalled = false;

            var container = ContainerFactory.New();

            container.ResolveUnregisteredType += (s, e) => { eventCalled = true; };

            try
            {
                // Act
                container.GetInstance <IUserRepository>();

                // Assert
                Assert.Fail("Exception was expected.");
            }
            catch (ActivationException)
            {
                Assert.IsTrue(eventCalled, "Before throwing an exception, the container must try to resolve " +
                              "a missing type by calling the ResolveUnregisteredType event.");
            }
        }