using Microsoft.AspNetCore.Mvc.ApplicationParts; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyModel; using System.Reflection; namespace zero.Architecture; public class AssemblyDiscovery : IAssemblyDiscovery { public static IAssemblyDiscovery Current; AssemblyDiscoveryContext Context; IMvcBuilder Mvc; public AssemblyDiscovery(IMvcBuilder mvc) { Mvc = mvc; Context = new AssemblyDiscoveryContext(); Current = this; } /// public void Execute(IEnumerable rules) { List assemblies = new List(); DependencyContext dependencyContext = DependencyContext.Load(Context.EntryAssembly); if (dependencyContext == null) { return; } string[] existingLibs = Mvc.PartManager.ApplicationParts.OfType().Select(p => p.Name).ToArray(); IEnumerable libraries = dependencyContext.RuntimeLibraries.Where(lib => !existingLibs.Contains(lib.Name, StringComparer.OrdinalIgnoreCase)); foreach (RuntimeLibrary library in libraries) { if (rules.Any(rule => rule.IsValid(library, Context))) { IEnumerable libraryAssemblies = library.GetDefaultAssemblyNames(dependencyContext).Select(name => Assembly.Load(name)); foreach (Assembly assembly in libraryAssemblies) { Mvc.AddApplicationPart(assembly); } } } } /// public void AddAssembly(Assembly assembly) { string[] existingLibs = Mvc.PartManager.ApplicationParts.OfType().Select(p => p.Name).ToArray(); if (!existingLibs.Contains(assembly.GetName().Name)) { Mvc.AddApplicationPart(assembly); } } /// public IEnumerable GetTypes(bool allowGenerics = false) => GetTypes(typeof(TService), allowGenerics); /// public IEnumerable GetTypes(IEnumerable parts, bool allowGenerics = false) => GetTypes(typeof(TService), parts, allowGenerics); /// public IEnumerable GetTypes(Type serviceType, bool allowGenerics = false) => GetAllClassTypes(allowGenerics).Where(t => serviceType.GetTypeInfo().IsAssignableFrom(t) && t.AsType() != serviceType); /// public IEnumerable GetTypes(Type serviceType, IEnumerable parts, bool allowGenerics = false) => GetAllClassTypes(parts, allowGenerics).Where(t => serviceType.GetTypeInfo().IsAssignableFrom(t) && t.AsType() != serviceType); /// public IEnumerable GetAllClassTypes(bool allowGenerics = false) => GetAllTypes().Where(t => t.IsClass && !t.IsAbstract && (allowGenerics || !t.ContainsGenericParameters)); /// public IEnumerable GetAllClassTypes(IEnumerable parts, bool allowGenerics = false) => GetAllTypes(parts).Where(t => t.IsClass && !t.IsAbstract && (allowGenerics || !t.ContainsGenericParameters)); /// public IEnumerable GetAssemblies() => Mvc.PartManager.ApplicationParts.OfType().Select(p => p.Assembly); /// public IEnumerable GetAssemblies(IEnumerable parts) => parts.OfType().Select(p => p.Assembly); /// public IEnumerable GetAllTypes() => Mvc.PartManager.ApplicationParts.OfType().SelectMany(p => p.Types); /// public IEnumerable GetAllTypes(IEnumerable parts) => parts.OfType().SelectMany(p => p.Types); } public interface IAssemblyDiscovery { /// /// Discovers runtime assemblies based on the given rules /// void Execute(IEnumerable rules); /// /// Manually add an assembly /// void AddAssembly(Assembly assembly); /// /// Get all discovered types which implement a certain service /// IEnumerable GetTypes(bool allowGenerics = false); /// /// Get all discovered types which implement a certain service /// IEnumerable GetTypes(IEnumerable parts, bool allowGenerics = false); /// /// Get all discovered types which implement a certain service /// IEnumerable GetTypes(Type serviceType, bool allowGenerics = false); /// /// Get all discovered types which implement a certain service /// IEnumerable GetTypes(Type serviceType, IEnumerable parts, bool allowGenerics = false); /// /// Get all registered types /// IEnumerable GetAllTypes(); /// /// Get all registered types /// IEnumerable GetAllTypes(IEnumerable parts); /// /// Get all registered types /// IEnumerable GetAllClassTypes(bool allowGenerics = false); /// /// Get all registered types /// IEnumerable GetAllClassTypes(IEnumerable parts, bool allowGenerics = false); /// /// Get all registered assemblies /// IEnumerable GetAssemblies(); /// /// Get all registered assemblies /// IEnumerable GetAssemblies(IEnumerable parts); }