// 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()); }
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))); }
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); }
/// <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)); }
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; } } }
/// <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>()); } }
/// <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); } }
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); }
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()); }
// 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))); }
public DependencyData(ParameterInfo parameter, Expression expression, InstanceProducer?producer) { this.Parameter = parameter; this.Expression = expression; this.Producer = producer; }