24 private static bool initialized;
25 private static readonly
object _lock =
new object();
27 private static readonly Dictionary<string, PlugInInstance> plugInClasses =
new Dictionary<string, PlugInInstance>();
28 private static readonly Dictionary<string, List<PlugInInstance>> queuePlugInClasses =
new Dictionary<string, List<PlugInInstance>>();
43 LoadReferencedAssemblies();
52 [ExcludeFromCodeCoverage]
53 private static void LoadReferencedAssemblies()
55 Assembly[] loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies();
58 foreach (Assembly assembly
in loadedAssemblies)
60 if (!assembly.IsDynamic && !
string.IsNullOrEmpty(assembly.Location))
64 RegisterPlugIns(assembly);
68 System.Diagnostics.Debug.WriteLine($
"Failed to register plugins from {assembly.Location}: {ex.Message}");
74 IEnumerable<string> allLoadedPaths = loadedAssemblies
75 .Where(a => !a.IsDynamic && !
string.IsNullOrEmpty(a.Location))
76 .Select(a => a.Location);
77 HashSet<string> loadedPaths =
new HashSet<string>(allLoadedPaths, StringComparer.InvariantCultureIgnoreCase);
79 List<string> referencedPaths = Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory,
"*.dll")
80 .Where(path => !loadedPaths.Contains(path))
83 foreach (
string path
in referencedPaths)
87 Assembly assembly = Assembly.LoadFrom(path);
88 RegisterPlugIns(assembly);
92 System.Diagnostics.Debug.WriteLine($
"Failed to load assembly: {path} - {ex.Message}");
102 internal static void InjectPlugins(List<Type> pluginTypes)
107 IEnumerable<Type> replacingPluginTypes = pluginTypes
108 .Where(t => t.GetCustomAttribute<NanoXlsxPlugInAttribute>() !=
null);
111 IEnumerable<Type> queuePluginTypes = pluginTypes
112 .Where(t => t.GetCustomAttributes<NanoXlsxQueuePlugInAttribute>().Any());
115 HandleReplacingPlugIns(replacingPluginTypes);
116 HandleQueuePlugIns(queuePluginTypes);
125 internal static void DisposePlugins()
129 plugInClasses.Clear();
130 queuePlugInClasses.Clear();
139 [ExcludeFromCodeCoverage]
140 private static void RegisterPlugIns(Assembly assembly)
142 IEnumerable<Type> replacingPlugInTypes = GetAssemblyPlugInsByType(assembly, typeof(NanoXlsxPlugInAttribute));
143 IEnumerable<Type> queuePlugInTypes = GetAssemblyPlugInsByType(assembly, typeof(NanoXlsxQueuePlugInAttribute));
144 HandleReplacingPlugIns(replacingPlugInTypes);
145 HandleQueuePlugIns(queuePlugInTypes);
155 [ExcludeFromCodeCoverage]
156 private static List<Type> GetAssemblyPlugInsByType(Assembly assembly, Type attributeType)
158 List<Type> plugInTypes =
new List<Type>();
159 Type plugInInterface = typeof(IPlugin);
160 Type[] allTypes = assembly.GetTypes();
162 for (
int i = 0; i < allTypes.Length; i++)
164 Type type = allTypes[i];
165 if (type.IsClass && !type.IsAbstract &&
166 plugInInterface.IsAssignableFrom(type) &&
167 type.GetCustomAttribute(attributeType) !=
null)
169 plugInTypes.Add(type);
179 [ExcludeFromCodeCoverage]
180 private static void HandleReplacingPlugIns(IEnumerable<Type> plugInTypes)
182 foreach (Type plugInType
in plugInTypes)
184 IEnumerable<NanoXlsxPlugInAttribute> attributes = plugInType.GetCustomAttributes<NanoXlsxPlugInAttribute>();
185 foreach (NanoXlsxPlugInAttribute attribute
in attributes)
187 if (plugInClasses.ContainsKey(attribute.
PlugInUUID))
195 else if (!plugInClasses.ContainsKey(attribute.
PlugInUUID))
207 private static void HandleQueuePlugIns(IEnumerable<Type> queuePlugInTypes)
209 foreach (Type plugInType
in queuePlugInTypes)
211 IEnumerable<NanoXlsxQueuePlugInAttribute> attributes = plugInType.GetCustomAttributes<NanoXlsxQueuePlugInAttribute>();
212 foreach (var attribute
in attributes)
214 if (!queuePlugInClasses.TryGetValue(attribute.QueueUUID, out var value))
216 value =
new List<PlugInInstance>();
217 queuePlugInClasses.Add(attribute.QueueUUID, value);
220 value.Add(
new PlugInInstance(attribute.PlugInUUID, attribute.PlugInOrder, plugInType));
224 foreach (KeyValuePair<
string, List<PlugInInstance>> entry
in queuePlugInClasses)
226 entry.Value.Sort((a, b) => a.Order.CompareTo(b.Order));
239 internal static T GetPlugIn<T>(
string plugInUUID, T fallBackInstance)
241 if (plugInClasses.TryGetValue(plugInUUID, out var plugIn))
243 return (T)Activator.CreateInstance(plugIn.Type,
true);
247 return fallBackInstance;
261 internal static T GetNextQueuePlugIn<T>(
string queueUUID,
string lastPlugInUUID, out
string currentPlugInUUID)
263 if (queuePlugInClasses.TryGetValue(queueUUID, out var plugInList) && plugInList.Count > 0)
265 PlugInInstance plugIn =
null;
266 if (lastPlugInUUID ==
null)
268 plugIn = plugInList[0];
273 int index = plugInList.FindIndex(p => p.UUID == lastPlugInUUID);
274 if (index >= 0 && index + 1 < plugInList.Count)
276 plugIn = plugInList[index + 1];
281 currentPlugInUUID =
null;
284 currentPlugInUUID = plugIn.UUID;
285 return (T)Activator.CreateInstance(plugIn.Type,
true);
289 currentPlugInUUID =
null;
297 private sealed class PlugInInstance
302 public string UUID {
get;
private set; }
306 public int Order {
get;
private set; }
311 public Type Type {
get;
private set; }
319 internal PlugInInstance(
string uuid,
int order, Type type)