using Medusa.Core.Services; using Microsoft.Extensions.DependencyInjection.Extensions; using System.Collections.Generic; using System.Reflection; namespace Medusa.Core.Extensions { public static class ServiceCollectionExtensions { /// /// Add handler service to DI /// /// The extended IServiceCollection /// public static IServiceCollection AddHandlers(this IServiceCollection services) { services.Add(new ServiceDescriptor(typeof(IHandlerService), typeof(HandlerService), ServiceLifetime.Singleton)); services.AddTransient(); return services; } /// /// Adds services implementing an interface to the DI container. /// /// The interface type /// The extended IServiceCollection /// The lifetime of the services /// public static IServiceCollection AddIServicesWithType(this IServiceCollection serviceCollection, ServiceLifetime lifetime = ServiceLifetime.Transient) { var assembly = typeof(TType).Assembly; var types = assembly.DefinedTypes .Where(x => typeof(TType).IsAssignableFrom(x) && !x.IsInterface && !x.IsAbstract) .ToArray(); if(types.Length == 0) return serviceCollection; foreach(var type in types) { serviceCollection.TryAdd(new ServiceDescriptor(typeof(TType), type.AsType(), lifetime)); } return serviceCollection; } /// /// Adds services from a namespace that implement an interface to the DI container. /// /// The extended IServiceCollection /// The namespace of the interfaces /// The lifetime of the services /// public static IServiceCollection AddServicesInNamespaceWithInterface(this IServiceCollection serviceCollection, string interfaceNamespace, ServiceLifetime lifetime = ServiceLifetime.Transient) { var assemblies = AppDomain.CurrentDomain.GetAssemblies(); var foundAssembly = assemblies.FirstOrDefault(x => x.DefinedTypes.Any(typeInfo => typeInfo.Namespace?.Equals(interfaceNamespace) ?? false)); if(foundAssembly == null) { try { var loaded = Assembly.Load(interfaceNamespace.Split('.')[0]); foundAssembly = loaded; } catch { return serviceCollection; } } var types = foundAssembly.DefinedTypes .Where(x => x.Namespace == interfaceNamespace && !x.IsInterface && !x.IsAbstract && !x.ContainsGenericParameters && !x.IsNested) .ToList(); if(types.Count == 0) return serviceCollection; foreach(var type in types) { var interfaceType = type.GetInterfaces().FirstOrDefault(); if(interfaceType != null) { serviceCollection.TryAdd(new ServiceDescriptor(interfaceType, type.AsType(), lifetime)); } } return serviceCollection; } /// /// Adds services from multiple namespaces to the DI container. /// /// The extended IServiceCollection /// List of namespaces /// The lifetime of the services /// public static IServiceCollection AddServicesInNamespaces(this IServiceCollection serviceCollection, string[] namespaces, ServiceLifetime lifetime = ServiceLifetime.Transient) { var assemblies = AppDomain.CurrentDomain.GetAssemblies(); var foundAssemblies = assemblies .Where(a => a.DefinedTypes.Any(t => namespaces.Contains(t.Namespace))) .ToList(); var notFoundNamespaces = namespaces.Except(foundAssemblies.SelectMany(a => a.GetTypes().Select(t => t.Namespace))).ToList(); var types = new List(); foreach(var assembly in foundAssemblies) { var foundTypes = assembly.DefinedTypes .Where(x => namespaces.Contains(x.Namespace) && !x.IsInterface && !x.IsAbstract && !x.IsNested) .ToArray(); types.AddRange(foundTypes); } foreach(var notFound in notFoundNamespaces) { try { var assemblyName = notFound?.Split('.')[0]; var assembly = Assembly.Load(assemblyName ?? ""); var foundTypes = assembly.DefinedTypes .Where(x => x.Namespace == notFound && !x.IsInterface && !x.IsAbstract && !x.IsNested) .ToArray(); types.AddRange(foundTypes); } catch { } } if(types.Count == 0) return serviceCollection; foreach(var type in types) { serviceCollection.TryAdd(new ServiceDescriptor(type.AsType(), type.AsType(), lifetime)); } return serviceCollection; } /// /// Adds services from a single namespace to the DI container. /// /// The extended IServiceCollection /// The namespace to scan /// The lifetime of the services /// public static IServiceCollection AddServicesInNamespace(this IServiceCollection serviceCollection, string @namespace, ServiceLifetime lifetime = ServiceLifetime.Transient) { var assemblies = AppDomain.CurrentDomain.GetAssemblies(); var assembly = assemblies.FirstOrDefault(x => x.DefinedTypes.Any(typeInfo => typeInfo.Namespace == @namespace)); var types = assembly?.DefinedTypes .Where(x => x.Namespace == @namespace && !x.IsInterface && !x.IsAbstract && !x.IsNested) .ToArray(); if(types == null || types.Length == 0) return serviceCollection; foreach(var type in types) { serviceCollection.TryAdd(new ServiceDescriptor(type.AsType(), type.AsType(), lifetime)); } return serviceCollection; } /// /// Adds a single class as a service to the DI container. /// /// The extended IServiceCollection /// The class type to add /// The lifetime of the service /// public static IServiceCollection CreateServiceFromClass(this IServiceCollection serviceCollection, Type serviceClassType, ServiceLifetime lifetime = ServiceLifetime.Transient) { serviceCollection.TryAdd(new ServiceDescriptor(serviceClassType, serviceClassType, lifetime)); return serviceCollection; } /// /// Adds multiple classes as services to the DI container. /// /// The extended IServiceCollection /// A list of class types /// The lifetime of the services /// public static IServiceCollection CreateServiceFromClasses(this IServiceCollection serviceCollection, IEnumerable serviceClassTypes, ServiceLifetime lifetime = ServiceLifetime.Transient) { foreach(var serviceClassType in serviceClassTypes) { serviceCollection.TryAdd(new ServiceDescriptor(serviceClassType, serviceClassType, lifetime)); } return serviceCollection; } /// /// Adds services based on a type that implements an interface, without adding the interface itself. /// /// The extended interface /// The extended IServiceCollection /// The lifetime of the services /// public static IServiceCollection AddServicesWithType(this IServiceCollection serviceDescriptors, ServiceLifetime lifetime = ServiceLifetime.Transient) { var assembly = typeof(TType).Assembly; var types = assembly.DefinedTypes .Where(x => typeof(TType).IsAssignableFrom(x) && !x.IsInterface && !x.IsAbstract) .ToArray(); if(types.Length == 0) return serviceDescriptors; foreach(var type in types) { serviceDescriptors.TryAdd(new ServiceDescriptor(type.AsType(), type.AsType(), lifetime)); } return serviceDescriptors; } } }