private String[] DiscoverPluginAssembliesHelper( String path, PluginCriteria criteria, Type criteriaType) { String[] assemblies; // Get .dll names path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, path); assemblies = Directory.GetFiles(path, "*.dll"); if(assemblies.Length != 0){ ArrayList assembliesIncluded = new ArrayList(); foreach(String s in assemblies){ // Load the assembly Assembly assembly = Assembly.LoadFrom(s); // Find matching type? Type[] types = assembly.GetTypes(); foreach(Type t in types){ if(IncludeType(t, criteria, criteriaType)){ assembliesIncluded.Add(s); break; // match found, move on } } } // Get array of matching assemblies assemblies = (String[])assembliesIncluded.ToArray( typeof(String)); } return assemblies; }
// Test a type for matching the plugin criteria private static Boolean IncludeType( Type type, PluginCriteria criteria, Type criteriaType) { Boolean judgement = false; // Switch on criteria type switch(criteria){ case PluginCriteria.Interface: // interface if(!criteriaType.IsInterface){ throw new ArgumentException( "Criteria does not match criteria type."); } // If compatible with the interface type, thumbs-up judgement = criteriaType.IsAssignableFrom(type); break; case PluginCriteria.BaseClass: if(!(criteriaType.IsClass && !criteriaType.IsSealed)){ throw new ArgumentException( "Criteria does not match criteria type."); } // If compatible with the base type, thumbs-up judgement = criteriaType.IsAssignableFrom(type); break; case PluginCriteria.CustomAttribute: if(!typeof(Attribute).IsAssignableFrom(criteriaType)){ throw new ArgumentException( "Criteria does not match criteria type."); } // If the attribute is defined on the type, then true judgement = type.IsDefined(criteriaType, true); break; default: throw new ArgumentException("Invalid plugin criteria."); } return judgement; }
// From an array of assemblies find the plugin types private static Type[] LoadPluginTypesHelper( String[] assemblies, PluginCriteria criteria, Type criteriaType) { ArrayList typesIncluded = new ArrayList(); foreach(String s in assemblies){ // Load the assembly Assembly assembly = Assembly.LoadFrom(s); // Find the plugin types Type[] types = assembly.GetExportedTypes(); foreach(Type t in types){ if(IncludeType(t, criteria, criteriaType)){ typesIncluded.Add(t); } } } // Return an array of types return (Type[])typesIncluded.ToArray(typeof(Type)); }
// Get an array of plugin types using a // plugin criteria and trust level public static Type[] LoadPluginTypes( PluginTrustLevel level, PluginCriteria criteria, Type criteriaType) { // Build the path for plugins we are searching for // also, if secure plugins won't work, throw String pluginPath; if(level == PluginTrustLevel.Full){ pluginPath = fullTrustPath; }else{ if(!supportSecurePlugins){ throw new SecurityException( "Semi-trusted plugins were not enabled!"); } pluginPath = semiTrustPath; } // Create a temporary app domain so that we can unload assemblies AppDomain domain = AppDomain.CreateDomain("TempDom"+Guid.NewGuid().ToString()); // Find the name of this assembly and load it into the domain String assemblyName = Assembly.GetExecutingAssembly().FullName; domain.Load(assemblyName); // Create an instance of the PluginManager type // in the temporary domain BindingFlags binding = BindingFlags.CreateInstance | BindingFlags.NonPublic | BindingFlags.Instance; ObjectHandle handle = domain.CreateInstance( assemblyName, typeof(PluginManager).ToString(), false, binding, null, null, null, null, null); PluginManager helper = (PluginManager)handle.Unwrap(); try{ // Get an array of assemblies that include matching plugins String[] assemblies= helper.DiscoverPluginAssembliesHelper( pluginPath, criteria, criteriaType); // return loaded plugin types return LoadPluginTypesHelper(assemblies, criteria, criteriaType); }catch(ReflectionTypeLoadException){ return new Type[0]; }finally{ // Unload any unwanted assemblies AppDomain.Unload(domain); } }