Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.IO;
- using System.Reflection;
- using System.Runtime.Loader;
- using System.Text.RegularExpressions;
- namespace MarkHub.Core.Infrastructure
- {
- /// <summary>
- /// A class that finds types needed by Grand by looping assemblies in the
- /// currently executing AppDomain. Only assemblies whose names matches
- /// certain patterns are investigated and an optional list of assemblies
- /// referenced by <see cref="AssemblyNames"/> are always investigated.
- /// </summary>
- public class AppDomainTypeFinder : ITypeFinder
- {
- #region Fields
- private bool loadAppDomainAssemblies = true;
- private string assemblySkipLoadingPattern = "^System|^mscorlib|^Microsoft|^Autofac|^AutoMapper|^Castle|^ComponentArt|^CppCodeProvider|^DotNetOpenAuth|^EPPlus|^FluentValidation|^ImageProcessor|^itextsharp|^log4net|^MaxMind|^MbUnit|^MiniProfiler|^Mono.Math|^MongoDB|^MvcContrib|^Newtonsoft|^NHibernate|^nunit|^Org.Mentalis|^PerlRegex|^QuickGraph|^Recaptcha|^Remotion|^RestSharp|^Iesi|^TestDriven|^TestFu|^UserAgentStringLibrary|^VJSharpCodeProvider|^WebDev|^WebGrease|^dotliquid|^fluentscheduler|^netstandard|^Google.Apis|^AWSSDK|^Braintree|^MediatR|^WebMarkupMin|^HealthChecks|^WebEssentials|^NWebsec|^NetEscapades|^Wangkanai|^dotnet-bundle|^MailKit|^MimeKit|^NUglify|^Pipelines.Sockets.Unofficial|^SharpCompress|^SkiaSharp|^StackExchange.Redis|^DnsClient|^BouncyCastle.Crypto|^AdvancedStringBuilder";
- private string assemblyRestrictToLoadingPattern = ".*";
- private IList<string> assemblyNames = new List<string>();
- #endregion
- #region Properties
- /// <summary>Gets or sets wether Nop should iterate assemblies in the app domain when loading Nop types. Loading patterns are applied when loading these assemblies.</summary>
- public bool LoadAppDomainAssemblies
- {
- get { return loadAppDomainAssemblies; }
- set { loadAppDomainAssemblies = value; }
- }
- /// <summary>Gets or sets assemblies loaded a startup in addition to those loaded in the AppDomain.</summary>
- public IList<string> AssemblyNames
- {
- get { return assemblyNames; }
- set { assemblyNames = value; }
- }
- /// <summary>Gets the pattern for dlls that we know don't need to be investigated.</summary>
- public string AssemblySkipLoadingPattern
- {
- get { return assemblySkipLoadingPattern; }
- set { assemblySkipLoadingPattern = value; }
- }
- /// <summary>Gets or sets the pattern for dll that will be investigated. For ease of use this defaults to match all but to increase performance you might want to configure a pattern that includes assemblies and your own.</summary>
- /// <remarks>If you change this so that Nop assemblies arn't investigated (e.g. by not including something like "^Nop|..." you may break core functionality.</remarks>
- public string AssemblyRestrictToLoadingPattern
- {
- get { return assemblyRestrictToLoadingPattern; }
- set { assemblyRestrictToLoadingPattern = value; }
- }
- #endregion
- #region Methods
- public IEnumerable<Type> FindClassesOfType<T>(bool onlyConcreteClasses = true)
- {
- return FindClassesOfType(typeof(T), onlyConcreteClasses);
- }
- public IEnumerable<Type> FindClassesOfType(Type assignTypeFrom, bool onlyConcreteClasses = true)
- {
- return FindClassesOfType(assignTypeFrom, GetAssemblies(), onlyConcreteClasses);
- }
- public IEnumerable<Type> FindClassesOfType<T>(IEnumerable<Assembly> assemblies, bool onlyConcreteClasses = true)
- {
- return FindClassesOfType(typeof (T), assemblies, onlyConcreteClasses);
- }
- public IEnumerable<Type> FindClassesOfType(Type assignTypeFrom, IEnumerable<Assembly> assemblies, bool onlyConcreteClasses = true)
- {
- var result = new List<Type>();
- try
- {
- foreach (var a in assemblies)
- {
- Type[] types = null;
- types = a.GetTypes();
- if (types == null)
- continue;
- foreach (var t in types)
- {
- if (!assignTypeFrom.IsAssignableFrom(t) && (!assignTypeFrom.IsGenericTypeDefinition || !DoesTypeImplementOpenGeneric(t, assignTypeFrom)))
- continue;
- if (t.IsInterface)
- continue;
- if (onlyConcreteClasses)
- {
- if (t.IsClass && !t.IsAbstract)
- {
- result.Add(t);
- }
- }
- else
- {
- result.Add(t);
- }
- }
- }
- }
- catch (ReflectionTypeLoadException ex)
- {
- var msg = string.Empty;
- foreach (var e in ex.LoaderExceptions)
- msg += e.Message + Environment.NewLine;
- var fail = new Exception(msg, ex);
- Debug.WriteLine(fail.Message, fail);
- throw fail;
- }
- return result;
- }
- // <summary>
- /// Does type implement generic?
- /// </summary>
- /// <param name="type"></param>
- /// <param name="openGeneric"></param>
- /// <returns></returns>
- protected virtual bool DoesTypeImplementOpenGeneric(Type type, Type openGeneric)
- {
- try
- {
- var genericTypeDefinition = openGeneric.GetGenericTypeDefinition();
- foreach (var implementedInterface in type.FindInterfaces((objType, objCriteria) => true, null))
- {
- if (!implementedInterface.IsGenericType)
- continue;
- var isMatch = genericTypeDefinition.IsAssignableFrom(implementedInterface.GetGenericTypeDefinition());
- return isMatch;
- }
- return false;
- }
- catch
- {
- return false;
- }
- }
- /// <summary>Gets the assemblies related to the current implementation.</summary>
- /// <returns>A list of assemblies that should be loaded by the Grand factory.</returns>
- public virtual IList<Assembly> GetAssemblies()
- {
- var addedAssemblyNames = new List<string>();
- var assemblies = new List<Assembly>();
- if (LoadAppDomainAssemblies)
- AddAssembliesInAppDomain(addedAssemblyNames, assemblies);
- AddConfiguredAssemblies(addedAssemblyNames, assemblies);
- return assemblies;
- }
- #endregion
- #region Utilities
- /// <summary>
- /// Iterates all assemblies in the AppDomain and if it's name matches the configured patterns add it to our list.
- /// </summary>
- /// <param name="addedAssemblyNames"></param>
- /// <param name="assemblies"></param>
- private void AddAssembliesInAppDomain(List<string> addedAssemblyNames, List<Assembly> assemblies)
- {
- foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
- {
- if (Matches(assembly.FullName))
- {
- if (!addedAssemblyNames.Contains(assembly.FullName))
- {
- assemblies.Add(assembly);
- addedAssemblyNames.Add(assembly.FullName);
- }
- }
- }
- }
- /// <summary>
- /// Adds specificly configured assemblies.
- /// </summary>
- /// <param name="addedAssemblyNames"></param>
- /// <param name="assemblies"></param>
- protected virtual void AddConfiguredAssemblies(List<string> addedAssemblyNames, List<Assembly> assemblies)
- {
- foreach (string assemblyName in AssemblyNames)
- {
- Assembly assembly = Assembly.Load(new AssemblyName(assemblyName));
- if (!addedAssemblyNames.Contains(assembly.FullName))
- {
- assemblies.Add(assembly);
- addedAssemblyNames.Add(assembly.FullName);
- }
- }
- }
- /// <summary>
- /// Check if a dll is one of the shipped dlls that we know don't need to be investigated.
- /// </summary>
- /// <param name="assemblyFullName">
- /// The name of the assembly to check.
- /// </param>
- /// <returns>
- /// True if the assembly should be loaded into MarkHub.
- /// </returns>
- public virtual bool Matches(string assemblyFullName)
- {
- return !Matches(assemblyFullName, AssemblySkipLoadingPattern)
- && Matches(assemblyFullName, AssemblyRestrictToLoadingPattern);
- }
- /// <summary>
- /// Check if a dll is one of the shipped dlls that we know don't need to be investigated.
- /// </summary>
- /// <param name="assemblyFullName">
- /// The assembly name to match.
- /// </param>
- /// <param name="pattern">
- /// The regular expression pattern to match against the assembly name.
- /// </param>
- /// <returns>
- /// True if the pattern matches the assembly name.
- /// </returns>
- protected virtual bool Matches(string assemblyFullName, string pattern)
- {
- return Regex.IsMatch(assemblyFullName, pattern, RegexOptions.IgnoreCase | RegexOptions.Compiled);
- }
- /// <summary>
- /// Makes sure matching assemblies in the supplied folder are loaded in the app domain.
- /// </summary>
- /// <param name="directoryPath">
- /// The physical path to a directory containing dlls to load in the app domain.
- /// </param>
- protected virtual void LoadMatchingAssemblies(string directoryPath)
- {
- var loadedAssemblyNames = new List<string>();
- foreach (Assembly a in GetAssemblies())
- {
- loadedAssemblyNames.Add(a.FullName);
- }
- if (!Directory.Exists(directoryPath))
- {
- return;
- }
- foreach (string dllPath in Directory.GetFiles(directoryPath, "*.dll"))
- {
- try
- {
- var shadowCopiedAssembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(dllPath);
- }
- catch (BadImageFormatException ex)
- {
- Trace.TraceError(ex.ToString());
- }
- }
- }
- #endregion
- }
- }
Add Comment
Please, Sign In to add comment