예제 #1
0
        // We're registering a service type after 'locking down' the container here and that means that the
        // type is added to a copy of the registrations dictionary and the original replaced with a new one.
        // This 'reference swapping' is thread-safe, but can result in types disappearing again from the
        // registrations when multiple threads simultaneously add different types. This however, does not
        // result in a consistency problem, because the missing type will be again added later. This type of
        // swapping safes us from using locks.
        private void AppendRootInstanceProducer(Type serviceType, InstanceProducer?rootProducer)
        {
            var snapshotCopy = this.rootProducerCache.MakeCopy();

            // This registration might already exist if it was added made by another thread. That's why we
            // need to use the indexer, instead of Add.
            snapshotCopy[serviceType] = rootProducer;

            // Prevent the compiler, JIT, and processor to reorder these statements to prevent the instance
            // producer from being added after the snapshot has been made accessible to other threads.
            // This is important on architectures with a weak memory model (such as ARM).
#if NETSTANDARD1_0 || NETSTANDARD1_3
            Interlocked.MemoryBarrier();
#else
            Thread.MemoryBarrier();
#endif

            // Replace the original with the new version that includes the serviceType (make snapshot public).
            this.rootProducerCache = snapshotCopy;

            if (rootProducer != null)
            {
                this.RemoveExternalProducer(rootProducer);
            }
        }
        /// <summary>Creates a controller.</summary>
        /// <param name="context">The Microsoft.AspNet.Mvc.ActionContext for the executing action.</param>
        /// <returns>A new controller instance.</returns>
        public object Create(ControllerContext context)
        {
            Type controllerType = context.ActionDescriptor.ControllerTypeInfo.AsType();

            InstanceProducer?producer =
                this.controllerProducers.GetOrAdd(controllerType, this.GetControllerProducer);

            if (producer is null)
            {
                throw new InvalidOperationException(
                          string.Format(
                              CultureInfo.InvariantCulture,
                              "For the {0} to function properly, it requires all controllers to be registered explicitly " +
                              "in Simple Injector, but a registration for {1} is missing. To ensure all controllers are " +
                              "registered properly, call the RegisterMvcControllers extension method on the Container " +
                              "from within your Startup.Configure method while supplying the IApplicationBuilder " +
                              "instance, e.g. \"this.container.RegisterMvcControllers(app);\".{2}" +
                              "Full controller name: {3}.",
                              typeof(SimpleInjectorControllerActivator).Name,
                              controllerType.ToFriendlyName(),
                              Environment.NewLine,
                              controllerType.FullName));
            }

            return(producer.GetInstance());
        }
예제 #3
0
        private object GetInstanceForRootType <TService>() where TService : class
        {
            InstanceProducer?producer = this.GetInstanceProducerForType <TService>(InjectionConsumerInfo.Root);

            this.AppendRootInstanceProducer(typeof(TService), producer);
            return(this.GetInstanceFromProducer(producer, typeof(TService)));
        }
예제 #4
0
        private ParameterDictionary <DependencyData> BuildConstructorParameters(ConstructorInfo constructor)
        {
            // NOTE: We used to use a LINQ query here (which is cleaner code), but we reverted back to using
            // a foreach statement to clean up the stack trace, since this is a very common code path to
            // show up in the stack trace and preventing showing up the Enumerable and Buffer`1 calls here
            // makes it easier for developers (and maintainers) to read the stack trace.
            var parameters = new ParameterDictionary <DependencyData>();

            foreach (ParameterInfo parameter in constructor.GetParameters())
            {
                var              consumer   = new InjectionConsumerInfo(parameter);
                Expression       expression = this.GetPlaceHolderFor(parameter);
                InstanceProducer?producer   = null;

                if (expression is null)
                {
                    producer   = this.Container.Options.GetInstanceProducerFor(consumer);
                    expression = producer.BuildExpression();
                }

                parameters.Add(parameter, new DependencyData(parameter, expression, producer));
            }

            return(parameters);
        }
예제 #5
0
        /// <summary>Creates a controller.</summary>
        /// <param name="context">The Microsoft.AspNet.Mvc.ActionContext for the executing action.</param>
        /// <returns>A new controller instance.</returns>
        public object Create(ControllerContext context)
        {
            Type controllerType = context.ActionDescriptor.ControllerTypeInfo.AsType();

            InstanceProducer?producer =
                this.controllerProducers.GetOrAdd(controllerType, this.GetControllerProducer);

            if (producer is null)
            {
                const string AddControllerActivationMethod =
                    nameof(SimpleInjectorAspNetCoreBuilderMvcCoreExtensions.AddControllerActivation);

                throw new InvalidOperationException(
                          $"For the {nameof(SimpleInjectorControllerActivator)} to function properly, it " +
                          $"requires all controllers to be registered explicitly, but a registration for " +
                          $"{controllerType.ToFriendlyName()} is missing. To find the controllers to register, " +
                          $"Simple Injector's {AddControllerActivationMethod} method makes use of ASP.NET Core's " +
                          $"Application Parts. The most likely cause of this missing controller is, therefore, " +
                          $"that {controllerType.ToFriendlyName()}'s assembly, namely " +
                          $"{controllerType.Assembly.GetName().Name}, is not registered as application part. For " +
                          $"more information about configuring application parts, please consult the official " +
                          $"Microsoft documentation at: " +
                          $"https://docs.microsoft.com/en-us/aspnet/core/mvc/advanced/app-parts.");
            }

            return(producer.GetInstance());
        }
        // We're registering a service type after 'locking down' the container here and that means that the
        // type is added to a copy of the registrations dictionary and the original replaced with a new one.
        // This 'reference swapping' is thread-safe, but can result in types disappearing again from the
        // registrations when multiple threads simultaneously add different types. This however, does not
        // result in a consistency problem, because the missing type will be again added later. This type of
        // swapping safes us from using locks.
        private void AppendRootInstanceProducer(Type serviceType, InstanceProducer?rootProducer)
        {
            Helpers.InterlockedAddAndReplace(ref this.rootProducerCache, serviceType, rootProducer);

            if (rootProducer != null)
            {
                this.RemoveExternalProducer(rootProducer);
            }
        }
 private void ThrowInvalidRegistrationException(Type serviceType, InstanceProducer?producer)
 {
     if (producer != null)
     {
         // Exception is never null in this context.
         throw producer.Exception !;
     }
     else
     {
         this.ThrowMissingInstanceProducerException(serviceType);
     }
 }
        private object GetInstanceFromProducer(InstanceProducer?instanceProducer, Type serviceType)
        {
            if (instanceProducer is null)
            {
                this.ThrowMissingInstanceProducerException(serviceType);
            }

            // We create the instance AFTER registering the instance producer. Registering the producer after
            // creating an instance, could make us loose all registrations that are done by GetInstance. This
            // will not have any functional effects, but can result in a performance penalty.
            return(instanceProducer !.GetInstance());
        }
        private object GetInstanceForRootType(Type serviceType)
        {
            if (serviceType.ContainsGenericParameters())
            {
                throw new ArgumentException(
                          StringResources.OpenGenericTypesCanNotBeResolved(serviceType), nameof(serviceType));
            }

            InstanceProducer?producer = this.GetInstanceProducerForType(serviceType, InjectionConsumerInfo.Root);

            this.AppendRootInstanceProducer(serviceType, producer);
            return(this.GetInstanceFromProducer(producer, serviceType));
        }
예제 #10
0
        private IEnumerable <InstanceProducer> GetInstanceProducers(InjectionConsumerInfo consumer)
        {
            bool handled = false;

            foreach (var provider in this.providers)
            {
                InstanceProducer?producer = provider.TryGetProducer(consumer, handled);

                if (producer != null)
                {
                    yield return(producer);

                    handled = true;
                }
            }
        }
예제 #11
0
        /// <inheritdoc />
        public IEnumerable <object> GetServices(Type serviceType, string contract = null)
        {
            try
            {
                return(_container.GetAllInstances(serviceType));
            }
            catch
            {
                InstanceProducer?registration = _container.GetRegistration(serviceType);
                if (registration != null)
                {
                    return(new object[] { registration.GetInstance() });
                }

                return(Enumerable.Empty <object>());
            }
        }
예제 #12
0
        /// <inheritdoc />
        public object GetService(Type serviceType, string contract = null)
        {
            try
            {
                InstanceProducer?registration = _container.GetRegistration(serviceType);
                if (registration != null)
                {
                    return(registration.GetInstance());
                }

                IEnumerable <object> registers = _container.GetAllInstances(serviceType);
                return(registers.LastOrDefault());
            }
            catch
            {
                return(null);
            }
        }
예제 #13
0
        private InstanceProducer BuildInstanceProducerForDependencyMetadata(Type metadataType)
        {
            Type serviceType = metadataType.GetGenericArguments()[0];

            InstanceProducer?instanceProducer =
                this.container.GetInstanceProducerForType(serviceType, InjectionConsumerInfo.Root);

            if (instanceProducer is null)
            {
                this.container.ThrowMissingInstanceProducerException(serviceType);
            }

            object metadata = CreateMetadata(metadataType, instanceProducer !);

            return(new InstanceProducer(
                       metadataType,
                       Lifestyle.Singleton.CreateRegistration(metadataType, metadata, this.container)));
        }
        public InstanceProducer?GetInstanceProducer(InjectionConsumerInfo consumer, bool throwOnFailure)
        {
            Requires.IsNotNull(consumer, nameof(consumer));

            InjectionTargetInfo target = consumer.Target;

            InstanceProducer?producer =
                this.container.GetRegistrationEvenIfInvalid(target.TargetType, consumer);

            if (producer == null && throwOnFailure)
            {
                // By redirecting to Verify() we let the verify throw an expressive exception. If it doesn't
                // we throw the exception ourselves.
                this.container.Options.DependencyInjectionBehavior.Verify(consumer);

                this.container.ThrowParameterTypeMustBeRegistered(target);
            }

            return(producer);
        }
예제 #15
0
        private InstanceProducer BuildMutableCollectionProducerFromUncontrolledCollection(
            Type serviceType, Type elementType)
        {
            InstanceProducer?enumerableProducer = this.GetRegistration(
                typeof(IEnumerable <>).MakeGenericType(elementType), throwOnFailure: true);
            Expression enumerableExpression = enumerableProducer !.BuildExpression();

            var expression = Expression.Call(
                method: serviceType.IsArray
                    ? EnumerableToArrayMethod.MakeGenericMethod(elementType)
                    : EnumerableToListMethod.MakeGenericMethod(elementType),
                arg0: enumerableExpression);

            Registration registration =
                new ExpressionRegistration(expression, serviceType, Lifestyle.Transient, this);

            return(new InstanceProducer(serviceType, registration)
            {
                IsContainerAutoRegistered = true
            });
        }
        /// <summary>
        /// Creates a Razor Page model activator.
        /// </summary>
        /// <param name="descriptor">The <see cref="CompiledPageActionDescriptor"/>.</param>
        /// <returns>The delegate used to activate the page model.</returns>
        public Func <PageContext, object> CreateActivator(CompiledPageActionDescriptor descriptor)
        {
            if (descriptor is null)
            {
                throw new ArgumentNullException(nameof(descriptor));
            }

            if (descriptor.ModelTypeInfo is null)
            {
                throw new ArgumentNullException(
                          nameof(descriptor.ModelTypeInfo) + " property cannot be null.",
                          nameof(descriptor));
            }

            Type pageModelType = descriptor.ModelTypeInfo.AsType();

            InstanceProducer?producer =
                this.pageModelProducers.GetOrAdd(pageModelType, this.GetPageModelProducer);

            if (producer is null)
            {
                throw new InvalidOperationException(
                          string.Format(
                              CultureInfo.InvariantCulture,
                              "For the {0} to function properly, it requires all page models to be registered explicitly " +
                              "in Simple Injector, but a registration for {1} is missing. To ensure all page models are " +
                              "registered properly, call the RegisterPageModels extension method on the Container " +
                              "from within your Startup.Configure method while supplying the IApplicationBuilder " +
                              "instance, e.g. \"this.container.RegisterPageModels(app);\".{2}" +
                              "Full page model name: {3}.",
                              typeof(SimpleInjectorPageModelActivatorProvider).Name,
                              pageModelType.ToFriendlyName(),
                              Environment.NewLine,
                              pageModelType.FullName));
            }

            return(_ => producer.GetInstance());
        }
예제 #17
0
        // Note that the 'implementationType' could in fact be a service type as well and it is allowed
        // for the implementationType to equal TService. This will happen when someone does the following:
        // container.Collections.Register<ILogger>(typeof(ILogger));
        private InstanceProducer GetOrCreateInstanceProducer(ContainerControlledItem item)
        {
            Type implementationType = item.ImplementationType;

            // If the implementationType is explicitly registered (using a Register call) we select this
            // producer (but we skip any implicit registrations or anything that is assignable, since
            // there could be more than one and it would be unclear which one to pick).
            InstanceProducer?producer = this.GetExplicitRegisteredInstanceProducer(implementationType);

            // If that doesn't result in a producer, we request a registration using unregistered type
            // resolution, were we prevent concrete types from being created by the container, since
            // the creation of concrete type would 'pollute' the list of registrations, and might result
            // in two registrations (since below we need to create a new instance producer out of it),
            // and that might cause duplicate diagnostic warnings.
            if (producer == null)
            {
                producer = this.GetInstanceProducerThroughUnregisteredTypeResolution(implementationType);
            }

            // If that still hasn't resulted in a producer, we create a new producer and return (or throw
            // an exception in case the implementation type is not a concrete type).
            if (producer == null)
            {
                return(this.CreateNewExternalProducer(item));
            }

            // If there is such a producer registered we return a new one with the service type.
            // This producer will be automatically registered as external producer.
            if (producer.ServiceType == typeof(TService))
            {
                return(producer);
            }

            return(new InstanceProducer(typeof(TService),
                                        new ExpressionRegistration(producer.BuildExpression(), this.container)));
        }
예제 #18
0
 public DependencyData(ParameterInfo parameter, Expression expression, InstanceProducer?producer)
 {
     this.Parameter  = parameter;
     this.Expression = expression;
     this.Producer   = producer;
 }