using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Runtime.Loader; using Oqtane.Modules; using Oqtane.Services; using Oqtane.Shared; using Oqtane.Themes; // ReSharper disable once CheckNamespace namespace System.Reflection { public static class AssemblyExtensions { public static IEnumerable GetInterfaces(this Assembly assembly) { if (assembly is null) { throw new ArgumentNullException(nameof(assembly)); } return assembly.GetTypes(typeof(TInterfaceType)); } public static IEnumerable GetTypes(this Assembly assembly, Type interfaceType) { if (assembly is null) { throw new ArgumentNullException(nameof(assembly)); } if (interfaceType is null) { throw new ArgumentNullException(nameof(interfaceType)); } return assembly.GetTypes() .Where(x => !x.IsInterface && !x.IsAbstract && interfaceType.IsAssignableFrom(x)); } public static IEnumerable GetTypes(this Assembly assembly) { return assembly.GetTypes(typeof(T)); } public static IEnumerable GetInstances(this Assembly assembly) where T : class { if (assembly is null) { throw new ArgumentNullException(nameof(assembly)); } var type = typeof(T); var list = assembly.GetTypes() .Where(x => !x.IsInterface && !x.IsAbstract && !x.IsGenericType && type.IsAssignableFrom(x)); foreach (var type1 in list) { if (Activator.CreateInstance(type1) is T instance) yield return instance; } } public static bool IsOqtaneAssembly(this Assembly assembly) { return assembly.FullName != null && (assembly.FullName.Contains("oqtane", StringComparison.OrdinalIgnoreCase)); } public static bool IsOqtaneAssembly(this FileInfo fileInfo) { return (fileInfo.Name.Contains("oqtane", StringComparison.OrdinalIgnoreCase)); } public static IEnumerable GetOqtaneAssemblies(this AppDomain appDomain) { return appDomain.GetAssemblies().Where(a => a.IsOqtaneAssembly()); } public static IEnumerable GetOqtaneClientAssemblies(this AppDomain appDomain) { return appDomain.GetOqtaneAssemblies() .Where(a => a.GetTypes().Any() || a.GetTypes().Any() || a.GetTypes().Any()) .Where(a => Utilities.GetFullTypeName(a.GetName().Name) != Constants.ClientId); } /// /// Checks if type should be ignored by oqtane dynamic loader /// /// Checked type /// public static bool IsOqtaneIgnore(this Type type) { return Attribute.IsDefined(type, typeof(OqtaneIgnoreAttribute)) || type.IsAbstract || type.IsGenericType; } public static void LoadOqtaneAssembly(this AssemblyLoadContext loadContext, FileInfo dll) { AssemblyName assemblyName = null; try { assemblyName = AssemblyName.GetAssemblyName(dll.FullName); } catch { Debug.WriteLine($"Oqtane Error: Cannot Get Assembly Name For {dll.Name}"); } loadContext.LoadOqtaneAssembly(dll, assemblyName); } public static void LoadOqtaneAssembly(this AssemblyLoadContext loadContext, FileInfo dll, AssemblyName assemblyName) { try { var pdb = Path.ChangeExtension(dll.FullName, ".pdb"); Assembly assembly = null; // load assembly ( and symbols ) from stream to prevent locking files ( as long as dependencies are in /bin they will load as well ) if (File.Exists(pdb)) { assembly = loadContext.LoadFromStream(new MemoryStream(File.ReadAllBytes(dll.FullName)), new MemoryStream(File.ReadAllBytes(pdb))); } else { assembly = loadContext.LoadFromStream(new MemoryStream(File.ReadAllBytes(dll.FullName))); } Debug.WriteLine($"Oqtane Info: Loaded Assembly {assemblyName}"); } catch (Exception ex) { Debug.WriteLine($"Oqtane Error: Unable To Load Assembly {assemblyName} - {ex}"); } } } }