Free cookie consent management tool by TermsFeed Policy Generator

source: branches/2924_DotNetCoreMigration/HeuristicLab.PluginInfrastructure/3.3/Isolation/AssemblyLoader.cs @ 16984

Last change on this file since 16984 was 16984, checked in by dpiringe, 5 years ago

#2924:

  • merged projects HeuristicLab.PluginInfrastructure.Runner and HeuristicLab.PluginInfrastructure
  • applied changes of code reviews (13.05.2019 and 22.05.2019) -> the old Runner is now RunnerHost and uses a Runner, which is executed on the child process
  • added Type GetType(string) to IApplicationManager and implemented it for LightweightApplicationManager
  • removed IActivator and IActivatorContext
  • deleted unused types like PluginDescriptionIterator
File size: 6.0 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.IO;
4using System.Linq;
5using System.Reflection;
6using System.Runtime.Loader;
7
8namespace HeuristicLab.PluginInfrastructure {
9
10  /// <summary>
11  /// Class to load assemblies.
12  /// </summary>
13  public class AssemblyLoader : IAssemblyLoader {
14    /// <summary>
15    /// Comparer for AssemblyNames.
16    /// </summary>
17    private class AssemblyNameComparer : IEqualityComparer<AssemblyName> {
18      private object concatProps(AssemblyName name) => name.FullName + name.Version.ToString();
19      public bool Equals(AssemblyName lhs, AssemblyName rhs) => concatProps(lhs).Equals(concatProps(rhs));
20      public int GetHashCode(AssemblyName obj) => concatProps(obj).GetHashCode();
21    }
22
23    #region Vars
24    private readonly IList<Assembly> assemblies = new List<Assembly>();
25    private readonly IList<Type> types = new List<Type>();
26    #endregion
27
28    #region Properties
29    /// <summary>
30    /// All loaded assemblies. Contains items only after a call of LoadAssemblies.
31    /// </summary>
32    public IEnumerable<Assembly> Assemblies => assemblies;
33
34    /// <summary>
35    /// All types found in all assemblies.
36    /// </summary>
37    public IEnumerable<Type> Types => types;
38    #endregion
39
40    #region Constructors
41    public AssemblyLoader() {
42
43      #region alternative code
44      /*
45      ScanTypesInBasePath();
46      Types = GetTypes();
47      */
48      /*
49      IEnumerable<Assembly> asms = CheckDependencies(GetLoadableAssemblies(GetAssembliesFromBasePath()));
50      LoadAssemblies(asms);
51      LoadTypes(asms);
52      */
53      //IEnumerable<Assembly> asms = GetLoadableAssemblies(GetAssembliesFromBasePath());
54      //LoadAssemblies(asms);
55      //LoadTypes(asms);
56      #endregion
57    }
58    #endregion
59
60
61    private IEnumerable<string> GetAssembliesFromBasePath(string basePath) {
62      return Directory.GetFiles(basePath, "*.dll", SearchOption.AllDirectories)
63        .Concat(Directory.GetFiles(basePath, "*.exe", SearchOption.AllDirectories));
64    }
65
66    #region alternative code
67    /*
68    // 2.
69    private IEnumerable<Assembly> GetLoadableAssemblies(IEnumerable<string> paths) {
70      IList<Assembly> assemblies = new List<Assembly>();     
71      foreach (string path in paths) {
72        try {
73          var asm = Assembly.LoadFile(path);
74          if (asm != null)
75            assemblies.Add(asm);
76          else
77            Console.WriteLine($"cannot load assembly with path={path}");
78        } catch (Exception e) {
79          Console.WriteLine($"exception occured for assembly with path={path}, type of exception={e.GetType()}");
80        }
81      }
82     
83      return assemblies;
84    }
85   
86    // 3.
87    private IEnumerable<Assembly> CheckDependencies(IEnumerable<Assembly> assemblies) {
88      IEqualityComparer<AssemblyName> comp = new AssemblyNameComparer();
89      IDictionary<AssemblyName, Assembly> dict = new Dictionary<AssemblyName, Assembly>(comp);
90
91      // fill dict
92      foreach (Assembly a in assemblies)
93        dict.Add(a.GetName(), a);
94
95      Parallel.ForEach(new List<Assembly>(dict.Values), asm => {
96        if (CheckDependencyRecursiveHelper(asm.GetName(), asm.GetReferencedAssemblies(), comp, dict))
97          lock(dict)
98            dict.Remove(asm.GetName());
99      });
100      return dict.Values;
101    }
102
103    private bool CheckDependencyRecursiveHelper(AssemblyName toCheck, IEnumerable<AssemblyName> refs, IEqualityComparer<AssemblyName> comp, IDictionary<AssemblyName, Assembly> dict) {
104      foreach(AssemblyName name in refs) {
105        if (comp.Equals(toCheck, name) || !dict.ContainsKey(name) || CheckDependencyRecursiveHelper(toCheck, dict[name].GetReferencedAssemblies(), comp, dict)) return true;
106      }
107      return false;
108    }
109   
110    // 4.
111    private void LoadAssemblies(IEnumerable<Assembly> assemblies) {
112
113      foreach (Assembly asm in assemblies) {
114        try {
115          Assemblies.Add(alc.LoadFromAssemblyName(asm.GetName()));
116        } catch(Exception e) { }
117      }
118    }
119    */
120    #endregion
121
122
123    private void LoadTypes(IEnumerable<Assembly> assemblies) {
124      foreach (Assembly asm in assemblies) {
125        try {
126          foreach (Type t in asm.GetExportedTypes()) {
127            types.Add(t);
128          }
129        } catch (ReflectionTypeLoadException e) {
130          // ReflectionTypeLoadException gets thrown if any class in a module cannot be loaded.
131          try {
132            foreach (Type t in e.Types) { // fetch the already loaded types, be careful some of them can be null
133              if (t != null) {
134                types.Add(t);
135              }
136            }
137          } catch (BadImageFormatException) { }
138        } catch (Exception e) { // to catch every other exception
139          //Tracing.Logger.Error(
140          //  $"Exception occured while loading types of assembly {asm.FullName}! \n " +
141          //  $"---- Stacktrace ---- \n {e}");
142        }
143      }
144    }
145
146    public IEnumerable<Assembly> LoadAssemblies(string basePath) {
147      foreach (string path in GetAssembliesFromBasePath(basePath))
148        LoadAssemblyFromPath(path);
149     
150      LoadTypes(this.Assemblies);
151      return this.Assemblies;
152    }
153
154    public IEnumerable<Assembly> LoadAssemblies(IEnumerable<AssemblyInfo> assemblyInfos) {
155      foreach (var info in assemblyInfos)
156        LoadAssemblyFromPath(info.Path.ToString());
157     
158      LoadTypes(this.Assemblies);
159      return this.Assemblies;
160    }
161
162    private void LoadAssemblyFromPath(string path) {
163      try {
164        var asm = AssemblyLoadContext.Default.LoadFromAssemblyPath(path); // loads assembly into default context
165        if (asm != null) {
166          assemblies.Add(asm);
167        } // else
168          //Tracing.Logger.Error($"Unnable to load assembly with path {path}!");
169      } catch (Exception e) { // to catch every exception occured by assembly loading.
170        //Tracing.Logger.Error(
171        //  $"Exception occured while loading assembly from path {path}! \n " +
172        //  $"---- Stacktrace ---- \n {e}");
173      }
174    }
175  }
176}
Note: See TracBrowser for help on using the repository browser.