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); }
/// <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); } }
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); }
/// <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); } }
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); }
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); }
/// <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); } }; }