Free cookie consent management tool by TermsFeed Policy Generator

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

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

#2924:

  • added IEnumerable<T> GetInstances<T>(params object[] args) where T: class and IEnumerable<object> GetInstances(Type type, params object[] args) method to IApplicationManager and implemented them in LightweightApplicationManager -> to instantiate types with specific constructor arguments
  • added RunnerState State { get; } property in IRunnerHost, was already in RunnerHost
  • added user authentication for NativeRunnerHost
  • added optional check for a running docker daemon and available image for type DockerRunnerHost + Exception DockerException
  • added caching of the saved IApplication in ApplicationRunner to prevent a new instance every get call
  • removed System.ServiceModel.Primitives NuGet package
  • lots of formatting
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    private void LoadTypes(IEnumerable<Assembly> assemblies) {
123      foreach (Assembly asm in assemblies) {
124        try {
125          foreach (Type t in asm.GetExportedTypes()) {
126            types.Add(t);
127          }
128        } catch (ReflectionTypeLoadException e) {
129          // ReflectionTypeLoadException gets thrown if any class in a module cannot be loaded.
130          try {
131            foreach (Type t in e.Types) { // fetch the already loaded types, be careful some of them can be null
132              if (t != null) {
133                types.Add(t);
134              }
135            }
136          } catch (BadImageFormatException) { }
137        } catch (Exception) { // to catch every other exception
138          //Tracing.Logger.Error(
139          //  $"Exception occured while loading types of assembly {asm.FullName}! \n " +
140          //  $"---- Stacktrace ---- \n {e}");
141        }
142      }
143    }
144
145    public IEnumerable<Assembly> LoadAssemblies(string basePath) {
146      foreach (string path in GetAssembliesFromBasePath(basePath))
147        LoadAssemblyFromPath(path);
148
149      LoadTypes(this.Assemblies);
150      return this.Assemblies;
151    }
152
153    public IEnumerable<Assembly> LoadAssemblies(IEnumerable<AssemblyInfo> assemblyInfos) {
154      foreach (var info in assemblyInfos)
155        LoadAssemblyFromPath(info.Path.ToString());
156
157      LoadTypes(this.Assemblies);
158      return this.Assemblies;
159    }
160
161    private void LoadAssemblyFromPath(string path) {
162      try {
163        var asm = AssemblyLoadContext.Default.LoadFromAssemblyPath(path); // loads assembly into default context
164        if (asm != null) {
165          assemblies.Add(asm);
166        } // else
167          //Tracing.Logger.Error($"Unnable to load assembly with path {path}!");
168      } catch (Exception) { // to catch every exception occured by assembly loading.
169        //Tracing.Logger.Error(
170        //  $"Exception occured while loading assembly from path {path}! \n " +
171        //  $"---- Stacktrace ---- \n {e}");
172      }
173    }
174  }
175}
Note: See TracBrowser for help on using the repository browser.