private static Registration CreateCrossWireRegistration(
            Container container, Type serviceType, IApplicationBuilder builder)
        {
            IServiceCollection services = GetServiceCollection(container);

            Lifestyle lifestyle = DetermineLifestyle(serviceType, services);

            Registration registration;

            if (lifestyle == Lifestyle.Singleton)
            {
                registration = lifestyle.CreateRegistration(
                    serviceType,
                    () => builder.ApplicationServices.GetRequiredService(serviceType),
                    container);
            }
            else
            {
                IHttpContextAccessor accessor = GetHttpContextAccessor(builder);

                registration = lifestyle.CreateRegistration(
                    serviceType,
                    () => GetServiceProvider(accessor, container).GetRequiredService(serviceType),
                    container);
            }

            if (lifestyle == Lifestyle.Transient && typeof(IDisposable).IsAssignableFrom(serviceType))
            {
                registration.SuppressDiagnosticWarning(DiagnosticType.DisposableTransientComponent,
                                                       justification: "This is a cross-wired service. ASP.NET Core will ensure it gets disposed.");
            }

            return(registration);
        }
Esempio n. 2
0
        /// <summary>
        /// Cross-wires an ASP.NET Core or third party service to the container, to allow the service to be
        /// injected into components that are built by the container.
        /// </summary>
        /// <param name="container">The container.</param>
        /// <param name="serviceType">The type of service object to ross-wire.</param>
        /// <param name="builder">The IApplicationBuilder to retrieve the service object from.</param>
        public static void CrossWire(this Container container, Type serviceType, IApplicationBuilder builder)
        {
            if (container == null)
            {
                throw new ArgumentNullException(nameof(container));
            }

            if (serviceType == null)
            {
                throw new ArgumentNullException(nameof(serviceType));
            }

            if (builder == null)
            {
                throw new ArgumentNullException(nameof(builder));
            }

            CrossWireContext context = GetCrossWireContext(container);

            Lifestyle lifestyle = DetermineLifestyle(serviceType, context.Services);

            Registration registration;

            if (lifestyle == Lifestyle.Singleton)
            {
                registration = lifestyle.CreateRegistration(
                    serviceType,
                    () => builder.ApplicationServices.GetRequiredService(serviceType),
                    container);
            }
            else
            {
                IHttpContextAccessor accessor = GetHttpContextAccessor(builder);

                EnsureServiceScopeIsRegistered(context, container, builder);

                registration = lifestyle.CreateRegistration(
                    serviceType,
                    () => GetServiceProvider(accessor, container).GetRequiredService(serviceType),
                    container);
            }

            if (lifestyle == Lifestyle.Transient && typeof(IDisposable).IsAssignableFrom(serviceType))
            {
                registration.SuppressDiagnosticWarning(DiagnosticType.DisposableTransientComponent,
                                                       justification: "This is a cross-wired service. ASP.NET Core will ensure it gets disposed.");
            }

            container.AddRegistration(serviceType, registration);
        }
        /// <summary>
        /// Registers all supplied <paramref name="implementationTypes"/> based on the closed-generic version
        /// of the given <paramref name="openGenericServiceType"/> with the given <paramref name="lifestyle"/>.
        /// </summary>
        /// <param name="openGenericServiceType">The definition of the open generic type.</param>
        /// <param name="implementationTypes">A list types to be registered.</param>
        /// <param name="lifestyle">The lifestyle to register instances with.</param>
        /// <exception cref="ArgumentNullException">Thrown when one of the arguments contain a null
        /// reference (Nothing in VB).</exception>
        /// <exception cref="ArgumentException">Thrown when <paramref name="openGenericServiceType"/> is not
        /// an open generic type or when one of the supplied types from the
        /// <paramref name="implementationTypes"/> collection does not derive from
        /// <paramref name="openGenericServiceType"/>.</exception>
        /// <exception cref="InvalidOperationException">Thrown when the given set of
        /// <paramref name="implementationTypes"/> contain multiple types that implement the same
        /// closed generic version of the given <paramref name="openGenericServiceType"/>.</exception>
        public void Register(Type openGenericServiceType, IEnumerable <Type> implementationTypes, Lifestyle lifestyle)
        {
            Requires.IsNotNull(openGenericServiceType, nameof(openGenericServiceType));
            Requires.IsNotNull(lifestyle, nameof(lifestyle));
            Requires.IsNotNull(implementationTypes, nameof(implementationTypes));
            Requires.IsGenericType(openGenericServiceType, nameof(openGenericServiceType),
                                   guidance: StringResources.SuppliedTypeIsNotGenericExplainingAlternativesWithTypes);
            Requires.IsNotPartiallyClosed(openGenericServiceType, nameof(openGenericServiceType));
            Requires.IsOpenGenericType(openGenericServiceType, nameof(openGenericServiceType),
                                       guidance: StringResources.SuppliedTypeIsNotOpenGenericExplainingAlternativesWithTypes);

            implementationTypes = implementationTypes.Distinct().ToArray();

            Requires.DoesNotContainNullValues(implementationTypes, nameof(implementationTypes));
            Requires.CollectionDoesNotContainOpenGenericTypes(implementationTypes, nameof(implementationTypes));
            Requires.ServiceIsAssignableFromImplementations(openGenericServiceType, implementationTypes,
                                                            nameof(implementationTypes), typeCanBeServiceType: false);

            var mappings =
                from mapping in BatchMapping.Build(openGenericServiceType, implementationTypes)
                let registration = lifestyle.CreateRegistration(mapping.ImplementationType, this)
                                   from serviceType in mapping.ClosedServiceTypes
                                   select new { serviceType, registration };

            foreach (var mapping in mappings)
            {
                this.AddRegistration(mapping.serviceType, mapping.registration);
            }
        }
Esempio n. 4
0
        private static Registration CreateCrossWireRegistration(
            SimpleInjectorAddOptions options,
            IServiceProvider provider,
            Type serviceType,
            Lifestyle lifestyle)
        {
            var registration = lifestyle.CreateRegistration(
                serviceType,
                lifestyle == Lifestyle.Singleton
                    ? BuildSingletonInstanceCreator(serviceType, provider)
                    : BuildScopedInstanceCreator(serviceType, options.ServiceProviderAccessor),
                options.Container);

            // This registration is managed and disposed by IServiceProvider and should, therefore, not be
            // disposed (again) by Simple Injector.
            registration.SuppressDisposal = true;

            if (lifestyle == Lifestyle.Transient && typeof(IDisposable).IsAssignableFrom(serviceType))
            {
                registration.SuppressDiagnosticWarning(
                    DiagnosticType.DisposableTransientComponent,
                    justification: "This is a cross-wired service. It will be disposed by IServiceScope.");
            }

            return(registration);
        }
Esempio n. 5
0
        /// <summary>
        /// Conditionally registers that an instance of <paramref name="implementationType"/> will be
        /// returned every time a <paramref name="serviceType"/> is requested and where the supplied
        /// <paramref name="predicate"/> returns true. The instance is cached according to the supplied
        /// <paramref name="lifestyle"/>. The predicate will only be evaluated a finite number of times; the
        /// predicate is unsuited for making decisions based on runtime conditions.
        /// </summary>
        /// <param name="serviceType">The base type or interface to register. This can be an open-generic type.</param>
        /// <param name="implementationType">The actual type that will be returned when requested.</param>
        /// <param name="lifestyle">The lifestyle that defines how returned instances are cached.</param>
        /// <param name="predicate">The predicate that determines whether the
        /// <paramref name="implementationType"/> can be applied for the requested service type. This predicate
        /// can be used to build a fallback mechanism where multiple registrations for the same service type
        /// are made. Note that the predicate will be called a finite number of times and its result will be cached
        /// for the lifetime of the container. It can't be used for selecting a type based on runtime conditions.
        /// </param>
        /// <exception cref="ArgumentNullException">Thrown when one of the arguments is a null reference
        /// (Nothing in VB).</exception>
        /// <exception cref="ArgumentException">Thrown when <paramref name="serviceType"/> and
        /// <paramref name="implementationType"/> are not a generic type or when <paramref name="serviceType"/>
        /// is a partially-closed generic type.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// Thrown when this container instance is locked and can not be altered.
        /// </exception>
        public void RegisterConditional(
            Type serviceType,
            Type implementationType,
            Lifestyle lifestyle,
            Predicate <PredicateContext> predicate)
        {
            Requires.IsNotNull(serviceType, nameof(serviceType));
            Requires.IsNotNull(implementationType, nameof(implementationType));
            Requires.IsNotNull(lifestyle, nameof(lifestyle));
            Requires.IsNotNull(predicate, nameof(predicate));
            Requires.IsNotPartiallyClosed(serviceType, nameof(serviceType), nameof(implementationType));

            Requires.ServiceOrItsGenericTypeDefinitionIsAssignableFromImplementation(
                serviceType, implementationType, nameof(serviceType));

            Requires.ImplementationHasSelectableConstructor(
                this, implementationType, nameof(implementationType));

            Requires.OpenGenericTypeDoesNotContainUnresolvableTypeArguments(
                serviceType, implementationType, nameof(implementationType));

            if (serviceType.ContainsGenericParameters())
            {
                this.RegisterOpenGeneric(serviceType, implementationType, lifestyle, predicate);
            }
            else
            {
                var registration = lifestyle.CreateRegistration(implementationType, this);
                this.RegisterConditional(serviceType, registration, predicate);
            }
        }
Esempio n. 6
0
        private void RegisterInterfaces(Type component, SimpleInjector.Lifestyle lifestyle)
        {
            var registration = lifestyle.CreateRegistration(component, _container);

            var interfaces = component.GetInterfaces();

            foreach (var serviceType in interfaces)
            {
                addRegistration(serviceType, registration);
            }
        }
        private static Registration CreateNonSingletonRegistration(
            Container container, Type serviceType, IApplicationBuilder app, Lifestyle lifestyle)
        {
            IHttpContextAccessor accessor = GetHttpContextAccessor(app);

            Registration registration = lifestyle.CreateRegistration(
                serviceType,
                () => GetServiceProvider(accessor, container, lifestyle).GetRequiredService(serviceType),
                container);

            if (lifestyle == Lifestyle.Transient && typeof(IDisposable).IsAssignableFrom(serviceType))
            {
                registration.SuppressDiagnosticWarning(
                    DiagnosticType.DisposableTransientComponent,
                    justification: "This is a cross-wired service. ASP.NET Core will ensure it gets disposed.");
            }

            return(registration);
        }
Esempio n. 8
0
        private static Registration CreateNonSingletonRegistration(
            Container container, Type serviceType, IServiceProvider appServices, Lifestyle lifestyle)
        {
            IHttpContextAccessor accessor = GetHttpContextAccessor(appServices);

            Registration registration = lifestyle.CreateRegistration(
                serviceType,
                () => GetServiceProvider(accessor, container, lifestyle).GetRequiredService(serviceType),
                container);

            // This registration is managed and disposed by IServiceProvider and should, therefore, not be
            // disposed (again) by Simple Injector.
            registration.SuppressDisposal = true;

            if (lifestyle == Lifestyle.Transient && typeof(IDisposable).IsAssignableFrom(serviceType))
            {
                registration.SuppressDiagnosticWarning(
                    DiagnosticType.DisposableTransientComponent,
                    justification:
                    "This is a cross-wired service. ASP.NET Core will ensure it gets disposed.");
            }

            return(registration);
        }
Esempio n. 9
0
        /// <summary>
        /// Allows registrations made using the <see cref="IServiceCollection"/> API to be resolved by Simple Injector.
        /// </summary>
        /// <param name="container">The container.</param>
        /// <param name="app">The <see cref="IApplicationBuilder"/> instance.</param>
        public static void AutoCrossWireAspNetComponents(this Container container, IApplicationBuilder app)
        {
            if (container == null)
            {
                throw new ArgumentNullException(nameof(container));
            }

            if (app == null)
            {
                throw new ArgumentNullException(nameof(app));
            }

            var services = (IServiceCollection)container.GetItem(CrossWireContextKey);

            if (services == null)
            {
                throw new InvalidOperationException(
                          "To use this method, please make sure cross-wiring is enabled, by invoking " +
                          $"the {nameof(EnableSimpleInjectorCrossWiring)} extension method as part of the " +
                          "ConfigureServices method of the Startup class. " +
                          "See https://simpleinjector.org/aspnetcore for more information.");
            }

            if (container.Options.DefaultScopedLifestyle == null)
            {
                throw new InvalidOperationException(
                          "To be able to allow auto cross-wiring, please ensure that the container is configured with a " +
                          "default scoped lifestyle by setting the Container.Options.DefaultScopedLifestyle property " +
                          "with the required scoped lifestyle for your type of application. In ASP.NET Core, the typical " +
                          $"lifestyle to use is the {nameof(AsyncScopedLifestyle)}. " +
                          "See: https://simpleinjector.org/lifestyles#scoped");
            }

            CrossWireServiceScope(container, app);

            IHttpContextAccessor accessor = GetHttpContextAccessor(app);

            container.ResolveUnregisteredType += (s, e) =>
            {
                if (e.Handled)
                {
                    return;
                }

                Type serviceType = e.UnregisteredServiceType;

                ServiceDescriptor descriptor = FindServiceDescriptor(services, serviceType);

                if (descriptor != null)
                {
                    Lifestyle lifestyle = ToLifestyle(descriptor.Lifetime);

                    // Create a cross-wire registration that calls back into the .NET Core container.
                    Registration registration = lifestyle.CreateRegistration(serviceType,
                                                                             () => GetServiceProvider(accessor, container).GetRequiredService(serviceType),
                                                                             container);

                    // Apply the required suppressions.
                    if (lifestyle == Lifestyle.Transient && typeof(IDisposable).IsAssignableFrom(serviceType))
                    {
                        registration.SuppressDiagnosticWarning(
                            DiagnosticType.DisposableTransientComponent,
                            justification: "This is a cross-wired service. ASP.NET will ensure it gets disposed.");
                    }

                    e.Register(registration);
                }
            };
        }