@@ -36,7 +36,7 @@ public abstract class Plugin : IDisposable
3636 /// The directory containing the plugin folders. Files can be contained in any subdirectory.
3737 /// </summary>
3838 public static readonly string PluginsDirectory =
39- Combine ( GetDirectoryName ( AppContext . BaseDirectory ) ! , "Plugins" ) ;
39+ Combine ( AppContext . BaseDirectory , "Plugins" ) ;
4040
4141 private static readonly FileSystemWatcher ? s_configWatcher ;
4242
@@ -96,7 +96,6 @@ static Plugin()
9696 s_configWatcher . Created += ConfigWatcher_Changed ;
9797 s_configWatcher . Renamed += ConfigWatcher_Changed ;
9898 s_configWatcher . Deleted += ConfigWatcher_Changed ;
99- AppDomain . CurrentDomain . AssemblyResolve += CurrentDomain_AssemblyResolve ;
10099 }
101100
102101 /// <summary>
@@ -126,36 +125,6 @@ private static void ConfigWatcher_Changed(object? sender, FileSystemEventArgs e)
126125 }
127126 }
128127
129- private static Assembly ? CurrentDomain_AssemblyResolve ( object ? sender , ResolveEventArgs args )
130- {
131- if ( args . Name . Contains ( ".resources" ) )
132- return null ;
133-
134- AssemblyName an = new ( args . Name ) ;
135-
136- var assembly = AppDomain . CurrentDomain . GetAssemblies ( ) . FirstOrDefault ( a => a . FullName == args . Name ) ??
137- AppDomain . CurrentDomain . GetAssemblies ( ) . FirstOrDefault ( a => a . GetName ( ) . Name == an . Name ) ;
138- if ( assembly != null ) return assembly ;
139-
140- var filename = an . Name + ".dll" ;
141- var path = filename ;
142- if ( ! File . Exists ( path ) ) path = Combine ( GetDirectoryName ( AppContext . BaseDirectory ) ! , filename ) ;
143- if ( ! File . Exists ( path ) ) path = Combine ( PluginsDirectory , filename ) ;
144- if ( ! File . Exists ( path ) && ! string . IsNullOrEmpty ( args . RequestingAssembly ? . GetName ( ) . Name ) )
145- path = Combine ( PluginsDirectory , args . RequestingAssembly ! . GetName ( ) . Name ! , filename ) ;
146- if ( ! File . Exists ( path ) ) return null ;
147-
148- try
149- {
150- return Assembly . Load ( File . ReadAllBytes ( path ) ) ;
151- }
152- catch ( Exception ex )
153- {
154- Utility . Log ( nameof ( Plugin ) , LogLevel . Error , ex ) ;
155- return null ;
156- }
157- }
158-
159128 public virtual void Dispose ( ) { }
160129
161130 /// <summary>
@@ -168,47 +137,52 @@ protected IConfigurationSection GetConfiguration()
168137 . GetSection ( "PluginConfiguration" ) ;
169138 }
170139
171- private static void LoadPlugin ( Assembly assembly )
140+ internal static void LoadPlugins ( )
172141 {
173- foreach ( var type in assembly . ExportedTypes )
142+ if ( Directory . Exists ( PluginsDirectory ) == false )
143+ return ;
144+
145+ var pluginDirs = Directory . GetDirectories ( PluginsDirectory ) ;
146+ var pluginAssemblyContext = new PluginAssemblyLoadContext ( pluginDirs ) ;
147+
148+ foreach ( var pluginPath in pluginDirs )
174149 {
175- if ( ! type . IsSubclassOf ( typeof ( Plugin ) ) ) continue ;
176- if ( type . IsAbstract ) continue ;
150+ var pluginName = GetFileName ( pluginPath ) ;
151+ var pluginFileName = Combine ( pluginPath , $ " { pluginName } .dll" ) ;
177152
178- var constructor = type . GetConstructor ( Type . EmptyTypes ) ;
179- if ( constructor == null ) continue ;
153+ if ( File . Exists ( pluginFileName ) == false )
154+ continue ;
180155
181- try
182- {
183- constructor . Invoke ( null ) ;
184- }
185- catch ( Exception ex )
186- {
187- Utility . Log ( nameof ( Plugin ) , LogLevel . Error , ex ) ;
188- }
189- }
190- }
156+ // Provides isolated, dynamic loading and unloading of assemblies and
157+ // their dependencies. Each ALC instance manages the resolution and
158+ // loading of assemblies and supports loading multiple versions of the
159+ // same assembly within a process by isolating them in different contexts.
160+ var assemblyName = new AssemblyName ( pluginName ) ;
161+ var pluginAssembly = pluginAssemblyContext . LoadFromAssemblyName ( assemblyName ) ;
191162
192- internal static void LoadPlugins ( )
193- {
194- if ( ! Directory . Exists ( PluginsDirectory ) ) return ;
195- List < Assembly > assemblies = [ ] ;
196- foreach ( var rootPath in Directory . GetDirectories ( PluginsDirectory ) )
197- {
198- foreach ( var filename in Directory . EnumerateFiles ( rootPath , "*.dll" , SearchOption . TopDirectoryOnly ) )
163+ var neoPluginClassType = pluginAssembly . ExportedTypes
164+ . FirstOrDefault (
165+ static f =>
166+ f . IsAssignableTo ( typeof ( Plugin ) ) && f . IsAbstract == false
167+ ) ;
168+
169+ if ( neoPluginClassType is not null )
199170 {
200- try
171+ var pluginClassConstructor = neoPluginClassType . GetConstructor ( Type . EmptyTypes ) ;
172+
173+ if ( pluginClassConstructor is not null )
201174 {
202- assemblies . Add ( Assembly . Load ( File . ReadAllBytes ( filename ) ) ) ;
175+ try
176+ {
177+ pluginClassConstructor . Invoke ( null ) ;
178+ }
179+ catch ( Exception ex )
180+ {
181+ Utility . Log ( $ "{ nameof ( Plugin ) } :{ pluginName } ", LogLevel . Error , ex . Message ) ;
182+ }
203183 }
204- catch { }
205184 }
206185 }
207-
208- foreach ( var assembly in assemblies )
209- {
210- LoadPlugin ( assembly ) ;
211- }
212186 }
213187
214188 /// <summary>
0 commit comments