using Microsoft.Extensions.DependencyInjection; using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using zero.Core.Assemblies; namespace zero.Core.Extensions { public static class ServiceCollectionExtensions { public static IAssemblyDiscovery ZeroAssemblyDiscovery { get; set; } /// /// Adds all found implementations based on the service type and assembly discovery rules /// public static void AddAll(this IServiceCollection services, ServiceLifetime lifetime = ServiceLifetime.Transient) => services.AddAll(typeof(TService), lifetime); /// /// Adds all found implementations based on the service type and assembly discovery rules /// public static void AddAll(this IServiceCollection services, Type serviceType, ServiceLifetime lifetime = ServiceLifetime.Transient) { if (ZeroAssemblyDiscovery == null) { throw new Exception("services.AddAll() can only be run after mvcBuilder.AddZero()"); } // add implementations with generic service types if (serviceType.GetTypeInfo().IsGenericTypeDefinition) { IEnumerable<(Type, TypeInfo)> matches = ZeroAssemblyDiscovery.GetConcreteTypes().SelectMany(type => { IEnumerable genericTypes = type.GetInterfaces().Select(x => x.GetTypeInfo()).Where(x => x.IsGenericType && x.GetGenericTypeDefinition() == serviceType); return genericTypes.Select(x => (x, type)); }); foreach ((Type, Type) match in matches) { services.Add(new ServiceDescriptor(match.Item1, match.Item2, lifetime)); } } // add implementations with specific service types else { foreach (Type type in ZeroAssemblyDiscovery.GetTypes(serviceType)) { services.Add(new ServiceDescriptor(serviceType, type, lifetime)); } } } /// /// Adds or overrides an implementation /// public static void Replace(this IServiceCollection services) where TService : class where TImplementation : class, TService { services.Remove(out ServiceLifetime lifetime); services.Add(new ServiceDescriptor(typeof(TService), typeof(TImplementation), lifetime)); } /// /// Adds or overrides an implementation /// public static void Replace(this IServiceCollection services, Func implementationFactory) where TService : class where TImplementation : class, TService { services.Remove(out ServiceLifetime lifetime); services.Add(new ServiceDescriptor(typeof(TService), implementationFactory, lifetime)); } /// /// Removes all instances of a registered service /// public static bool Remove(this IServiceCollection services) => services.Remove(out ServiceLifetime lifetime); /// /// Removes all instances of a registered service /// public static bool Remove(this IServiceCollection services, out ServiceLifetime lifetime) { Type serviceType = typeof(TService); IEnumerable descriptors = services.Where(x => x.ServiceType == serviceType); if (descriptors.Any()) { lifetime = descriptors.First().Lifetime; foreach (ServiceDescriptor descriptor in descriptors) { services.Remove(descriptor); } } else { lifetime = ServiceLifetime.Transient; } return descriptors.Any(); } } }