Changed file name of IAbstractFactory interface to match with conventions; refactored the assembly loading code into a separate class using an interface, this allows unit testing to simulate assembly loading errors easily and might help the actual application to act on assembly load errors if so required; all classes in the Nuclex.Support.Plugins namespace now have 100% test coverage
git-svn-id: file:///srv/devel/repo-conversion/nusu@104 d2e56fa2-650e-0410-a79f-9358c0239efd
This commit is contained in:
		
							parent
							
								
									88b51ef0fa
								
							
						
					
					
						commit
						447fe2aea7
					
				
					 7 changed files with 330 additions and 57 deletions
				
			
		|  | @ -123,16 +123,14 @@ | |||
|     <Compile Include="Source\PathHelper.Test.cs"> | ||||
|       <DependentUpon>PathHelper.cs</DependentUpon> | ||||
|     </Compile> | ||||
|     <Compile Include="Source\Plugins\AbstractFactory.cs" /> | ||||
|     <Compile Include="Source\Plugins\AbstractFactory.Test.cs"> | ||||
|       <DependentUpon>AbstractFactory.cs</DependentUpon> | ||||
|     </Compile> | ||||
|     <Compile Include="Source\Plugins\IAbstractFactory.cs" /> | ||||
|     <Compile Include="Source\Plugins\Employer.Test.cs"> | ||||
|       <DependentUpon>Employer.cs</DependentUpon> | ||||
|     </Compile> | ||||
|     <Compile Include="Source\Plugins\FactoryEmployer.Test.cs"> | ||||
|       <DependentUpon>FactoryEmployer.cs</DependentUpon> | ||||
|     </Compile> | ||||
|     <Compile Include="Source\Plugins\IAssemblyLoader.cs" /> | ||||
|     <Compile Include="Source\Plugins\InstanceEmployer.Test.cs"> | ||||
|       <DependentUpon>InstanceEmployer.cs</DependentUpon> | ||||
|     </Compile> | ||||
|  |  | |||
|  | @ -19,21 +19,22 @@ License along with this library | |||
| #endregion | ||||
| 
 | ||||
| using System; | ||||
| using System.IO; | ||||
| 
 | ||||
| #if UNITTEST | ||||
| 
 | ||||
| using NUnit.Framework; | ||||
| using NUnit.Framework.SyntaxHelpers; | ||||
| using System.Collections.Generic; | ||||
| using System.Reflection; | ||||
| 
 | ||||
| namespace Nuclex.Support.Plugins { | ||||
| 
 | ||||
|   /// <summary>Unit Test for the abstract factory interface</summary> | ||||
|   [TestFixture] | ||||
|   public class AbtractFactoryTest { | ||||
|   /// <summary>Interface for an assembly loading helper</summary> | ||||
|   public interface IAssemblyLoader { | ||||
| 
 | ||||
|     /// <summary>Tries to loads an assembly from a file</summary> | ||||
|     /// <param name="path">Path to the file that is loaded as an assembly</param> | ||||
|     /// <param name="loadedAssembly"> | ||||
|     ///   Output parameter that receives the loaded assembly or null | ||||
|     /// </param> | ||||
|     /// <returns>True if the assembly was loaded successfully, otherwise false</returns> | ||||
|     bool TryLoadFile(string path, out Assembly loadedAssembly); | ||||
| 
 | ||||
|   } | ||||
| 
 | ||||
| } // namespace Nuclex.Support.Plugins | ||||
| 
 | ||||
| #endif // UNITTEST | ||||
|  | @ -20,6 +20,7 @@ License along with this library | |||
| 
 | ||||
| using System; | ||||
| using System.IO; | ||||
| using System.Reflection; | ||||
| 
 | ||||
| #if UNITTEST | ||||
| 
 | ||||
|  | @ -29,8 +30,133 @@ using NUnit.Framework.SyntaxHelpers; | |||
| namespace Nuclex.Support.Plugins { | ||||
| 
 | ||||
|   /// <summary>Unit Test for the plugin host class</summary> | ||||
|   [TestFixture] | ||||
|   [TestFixture, NoPlugin] // NoPlugin is used in one of the unit tests | ||||
|   public class PluginHostTest { | ||||
| 
 | ||||
|     #region class FailingEmployer | ||||
| 
 | ||||
|     /// <summary>Employer that unexpectedly fails to employ a given type</summary> | ||||
|     private class FailingEmployer : Employer { | ||||
| 
 | ||||
|       /// <summary>Employs the specified plugin type</summary> | ||||
|       /// <param name="type">Type to be employed</param> | ||||
|       public override void Employ(Type type) { | ||||
|         if(type.Equals(typeof(PluginRepository))) { | ||||
|           throw new InvalidOperationException(); | ||||
|         } | ||||
|       } | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     #endregion // class FailingEmployer | ||||
| 
 | ||||
|     /// <summary>Tests whether the simple constructor is working</summary> | ||||
|     [Test] | ||||
|     public void TestSimpleConstructor() { | ||||
|       new PluginHost(new FactoryEmployer<PluginHostTest>()); | ||||
|     } | ||||
| 
 | ||||
|     /// <summary>Tests whether the full constructor is working</summary> | ||||
|     [Test] | ||||
|     public void TestFullConstructor() { | ||||
|       new PluginHost(new FactoryEmployer<PluginHostTest>(), new PluginRepository()); | ||||
|     } | ||||
| 
 | ||||
|     /// <summary> | ||||
|     ///   Tests whether the AddAssembly() method works by adding the test assembly | ||||
|     ///   itself to the repository | ||||
|     /// </summary> | ||||
|     [Test] | ||||
|     public void TestFullConstructorWithPreloadedAssembly() { | ||||
|       PluginRepository testRepository = new PluginRepository(); | ||||
|       FactoryEmployer<PluginRepository> testEmployer = new FactoryEmployer<PluginRepository>(); | ||||
| 
 | ||||
|       // Might also use Assembly.GetCallingAssembly() here, but this leads to the exe of | ||||
|       // the unit testing tool | ||||
|       Assembly self = Assembly.GetAssembly(GetType()); | ||||
|       testRepository.AddAssembly(self); | ||||
| 
 | ||||
|       PluginHost testHost = new PluginHost(testEmployer, testRepository); | ||||
| 
 | ||||
|       Assert.AreEqual(1, testEmployer.Factories.Count); | ||||
|     } | ||||
| 
 | ||||
|     /// <summary> | ||||
|     ///   Verifies that the plugin host correctly stores the provided repository | ||||
|     /// </summary> | ||||
|     [Test] | ||||
|     public void TestRepositoryStorage() { | ||||
|       PluginRepository testRepository = new PluginRepository(); | ||||
|       FactoryEmployer<PluginRepository> testEmployer = new FactoryEmployer<PluginRepository>(); | ||||
|       PluginHost testHost = new PluginHost(testEmployer, testRepository); | ||||
| 
 | ||||
|       Assert.AreSame(testRepository, testHost.Repository); | ||||
|     } | ||||
| 
 | ||||
|     /// <summary> | ||||
|     ///   Verifies that the plugin host correctly stores the provided employer | ||||
|     /// </summary> | ||||
|     [Test] | ||||
|     public void TestEmployerStorage() { | ||||
|       PluginRepository testRepository = new PluginRepository(); | ||||
|       FactoryEmployer<PluginRepository> testEmployer = new FactoryEmployer<PluginRepository>(); | ||||
|       PluginHost testHost = new PluginHost(testEmployer, testRepository); | ||||
| 
 | ||||
|       Assert.AreSame(testEmployer, testHost.Employer); | ||||
|     } | ||||
| 
 | ||||
|     /// <summary> | ||||
|     ///   Tests whether the plugin host noticed when new assemblies are loaded into | ||||
|     ///   the repository | ||||
|     /// </summary> | ||||
|     [Test] | ||||
|     public void TestAssemblyLoading() { | ||||
|       PluginRepository testRepository = new PluginRepository(); | ||||
|       FactoryEmployer<PluginRepository> testEmployer = new FactoryEmployer<PluginRepository>(); | ||||
| 
 | ||||
|       PluginHost testHost = new PluginHost(testEmployer, testRepository); | ||||
| 
 | ||||
|       // Might also use Assembly.GetCallingAssembly() here, but this leads to the exe of | ||||
|       // the unit testing tool | ||||
|       Assembly self = Assembly.GetAssembly(GetType()); | ||||
|       testRepository.AddAssembly(self); | ||||
| 
 | ||||
|       Assert.AreEqual(1, testEmployer.Factories.Count); | ||||
|     } | ||||
| 
 | ||||
|     /// <summary> | ||||
|     ///   Tests whether the plugin host isolates the caller from an exception when the | ||||
|     ///   employer fails to employ a type in the assembly | ||||
|     /// </summary> | ||||
|     [Test] | ||||
|     public void TestAssemblyLoadingWithEmployFailure() { | ||||
|       PluginRepository testRepository = new PluginRepository(); | ||||
|       PluginHost testHost = new PluginHost(new FailingEmployer(), testRepository); | ||||
| 
 | ||||
|       // Might also use Assembly.GetCallingAssembly() here, but this leads to the exe of | ||||
|       // the unit testing tool | ||||
|       Assembly self = Assembly.GetAssembly(GetType()); | ||||
|       testRepository.AddAssembly(self); | ||||
|     } | ||||
| 
 | ||||
|     /// <summary> | ||||
|     ///   Verifies that the plugin host ignores types which have the NoPluginAttribute | ||||
|     ///   assigned to them | ||||
|     /// </summary> | ||||
|     [Test] | ||||
|     public void TestAssemblyLoadingWithNoPluginAttribute() { | ||||
|       PluginRepository testRepository = new PluginRepository(); | ||||
|       FactoryEmployer<PluginHostTest> testEmployer = new FactoryEmployer<PluginHostTest>(); | ||||
|       PluginHost testHost = new PluginHost(testEmployer, testRepository); | ||||
| 
 | ||||
|       // Might also use Assembly.GetCallingAssembly() here, but this leads to the exe of | ||||
|       // the unit testing tool | ||||
|       Assembly self = Assembly.GetAssembly(GetType()); | ||||
|       testRepository.AddAssembly(self); | ||||
| 
 | ||||
|       Assert.AreEqual(0, testEmployer.Factories.Count); | ||||
|     } | ||||
| 
 | ||||
|   } | ||||
| 
 | ||||
| } // namespace Nuclex.Support.Plugins | ||||
|  |  | |||
|  | @ -19,6 +19,7 @@ License along with this library | |||
| #endregion | ||||
| 
 | ||||
| using System; | ||||
| using System.Diagnostics; | ||||
| using System.Reflection; | ||||
| 
 | ||||
| namespace Nuclex.Support.Plugins { | ||||
|  | @ -83,10 +84,8 @@ namespace Nuclex.Support.Plugins { | |||
| 
 | ||||
|         // Types that have been tagged with the [NoPlugin] attribute will be ignored | ||||
|         object[] attributes = type.GetCustomAttributes(true); | ||||
|         for(int index = 0; index < attributes.Length; ++index) { | ||||
|           if(attributes[index] is NoPluginAttribute) { | ||||
|             continue; | ||||
|           } | ||||
|         if(containsNoPluginAttribute(attributes)) { | ||||
|           continue; | ||||
|         } | ||||
| 
 | ||||
|         // Type seems to be acceptable, assess and possibly employ it | ||||
|  | @ -96,14 +95,26 @@ namespace Nuclex.Support.Plugins { | |||
|           } | ||||
|         } | ||||
|         catch(Exception exception) { | ||||
|           System.Console.WriteLine( | ||||
|             "Could not employ " + type.ToString() + ": " + exception.Message | ||||
|           ); | ||||
|           Trace.WriteLine("Could not employ " + type.ToString() + ": " + exception.Message); | ||||
|         } | ||||
| 
 | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     /// <summary> | ||||
|     ///   Determines whether the specifies list of attributes contains a NoPluginAttribute | ||||
|     /// </summary> | ||||
|     /// <param name="attributes">List of attributes to check</param> | ||||
|     /// <returns>True if the list contained a NoPluginAttribute, false otherwise</returns> | ||||
|     private static bool containsNoPluginAttribute(object[] attributes) { | ||||
|       for(int index = 0; index < attributes.Length; ++index) { | ||||
|         if(attributes[index] is NoPluginAttribute) { | ||||
|           return true; | ||||
|         } | ||||
|       } | ||||
|       return false; | ||||
|     } | ||||
| 
 | ||||
|     /// <summary>Employs and manages types in the loaded plugin assemblies</summary> | ||||
|     private Employer employer; | ||||
|     /// <summary>Repository containing all plugins loaded, shared with other hosts</summary> | ||||
|  |  | |||
|  | @ -19,6 +19,7 @@ License along with this library | |||
| #endregion | ||||
| 
 | ||||
| using System; | ||||
| using System.Diagnostics; | ||||
| using System.IO; | ||||
| using System.Reflection; | ||||
| 
 | ||||
|  | @ -53,6 +54,40 @@ namespace Nuclex.Support.Plugins { | |||
| 
 | ||||
|     #endregion // interface IProgressTrackerSubscriber | ||||
| 
 | ||||
|     #region class TestAssemblyLoader | ||||
| 
 | ||||
|     /// <summary>Special assembly loader for the unit test</summary> | ||||
|     public class TestAssemblyLoader : PluginRepository.DefaultAssemblyLoader { | ||||
| 
 | ||||
|       /// <summary>Loads an assembly from a file system path</summary> | ||||
|       /// <param name="path">Path the assembly will be loaded from</param> | ||||
|       /// <returns>The loaded assembly</returns> | ||||
|       protected override Assembly LoadAssemblyFromFile(string path) { | ||||
|         switch(path) { | ||||
|           case "DllNotFound": { | ||||
|             Trace.WriteLine("Simulating DllNotFoundException for unit test"); | ||||
|             throw new DllNotFoundException(); | ||||
|           } | ||||
|           case "UnauthorizedAccess": { | ||||
|             Trace.WriteLine("Simulating UnauthorizedAccessException for unit test"); | ||||
|             throw new UnauthorizedAccessException(); | ||||
|           } | ||||
|           case "BadImageFormat": { | ||||
|             Trace.WriteLine("Simulating BadImageFormatException for unit test"); | ||||
|             throw new BadImageFormatException(); | ||||
|           } | ||||
|           case "IO": { | ||||
|             Trace.WriteLine("Simulating IOException for unit test"); | ||||
|             throw new IOException(); | ||||
|           } | ||||
|           default: { return Assembly.LoadFile(path); } | ||||
|         } | ||||
|       } | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     #endregion // class TestAssemblyLoader | ||||
| 
 | ||||
|     /// <summary> | ||||
|     ///   Tests whether the default constructor of the plugin repository class works | ||||
|     /// </summary> | ||||
|  | @ -81,6 +116,8 @@ namespace Nuclex.Support.Plugins { | |||
| 
 | ||||
|       Assembly self = Assembly.GetAssembly(GetType()); | ||||
|       testRepository.AddFiles(self.Location); | ||||
| 
 | ||||
|       Assert.AreEqual(1, testRepository.LoadedAssemblies.Count); | ||||
|     } | ||||
| 
 | ||||
|     /// <summary> | ||||
|  | @ -118,6 +155,50 @@ namespace Nuclex.Support.Plugins { | |||
|       mockery.VerifyAllExpectationsHaveBeenMet(); | ||||
|     } | ||||
| 
 | ||||
|     /// <summary> | ||||
|     ///   Verifies that no exceptions come through when a DllNotFoundException is thrown | ||||
|     ///   during assembly loading | ||||
|     /// </summary> | ||||
|     [Test] | ||||
|     public void TestDllNotFoundExceptionDuringAssemblyLoad() { | ||||
|       TestAssemblyLoader loader = new TestAssemblyLoader(); | ||||
|       Assembly loadedAssembly; | ||||
|       Assert.IsFalse(loader.TryLoadFile("DllNotFound", out loadedAssembly)); | ||||
|     } | ||||
| 
 | ||||
|     /// <summary> | ||||
|     ///   Verifies that no exceptions come through when a UnauthorizedAccessException is | ||||
|     ///   thrown during assembly loading | ||||
|     /// </summary> | ||||
|     [Test] | ||||
|     public void TestUnauthorizedAccessExceptionDuringAssemblyLoad() { | ||||
|       TestAssemblyLoader loader = new TestAssemblyLoader(); | ||||
|       Assembly loadedAssembly; | ||||
|       Assert.IsFalse(loader.TryLoadFile("UnauthorizedAccess", out loadedAssembly)); | ||||
|     } | ||||
| 
 | ||||
|     /// <summary> | ||||
|     ///   Verifies that no exceptions come through when a BadImageFormatException is | ||||
|     ///   thrown during assembly loading | ||||
|     /// </summary> | ||||
|     [Test] | ||||
|     public void TestBadImageFormatExceptionDuringAssemblyLoad() { | ||||
|       TestAssemblyLoader loader = new TestAssemblyLoader(); | ||||
|       Assembly loadedAssembly; | ||||
|       Assert.IsFalse(loader.TryLoadFile("BadImageFormat", out loadedAssembly)); | ||||
|     } | ||||
| 
 | ||||
|     /// <summary> | ||||
|     ///   Verifies that no exceptions come through when an IOException is | ||||
|     ///   thrown during assembly loading | ||||
|     /// </summary> | ||||
|     [Test] | ||||
|     public void TestIOExceptionDuringAssemblyLoad() { | ||||
|       TestAssemblyLoader loader = new TestAssemblyLoader(); | ||||
|       Assembly loadedAssembly; | ||||
|       Assert.IsFalse(loader.TryLoadFile("IO", out loadedAssembly)); | ||||
|     } | ||||
| 
 | ||||
|     /// <summary>Mocks a subscriber for the events of a plugin repository</summary> | ||||
|     /// <param name="mockery">Mockery to create an event subscriber in</param> | ||||
|     /// <param name="repository">Repository to subscribe the mocked subscriber to</param> | ||||
|  |  | |||
|  | @ -20,8 +20,9 @@ License along with this library | |||
| 
 | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Reflection; | ||||
| using System.Diagnostics; | ||||
| using System.IO; | ||||
| using System.Reflection; | ||||
| 
 | ||||
| namespace Nuclex.Support.Plugins { | ||||
| 
 | ||||
|  | @ -33,12 +34,94 @@ namespace Nuclex.Support.Plugins { | |||
|   /// </remarks> | ||||
|   public class PluginRepository { | ||||
| 
 | ||||
|     #region class DefaultAssemblyLoader | ||||
| 
 | ||||
|     /// <summary>Default assembly loader used to read assemblies from files</summary> | ||||
|     public class DefaultAssemblyLoader : IAssemblyLoader { | ||||
| 
 | ||||
|       /// <summary>Initializes a new default assembly loader</summary> | ||||
|       /// <remarks> | ||||
|       ///   Made protected to provide users with a small incentive for using | ||||
|       ///   the Instance property instead of creating new instances all around. | ||||
|       /// </remarks> | ||||
|       protected DefaultAssemblyLoader() { } | ||||
| 
 | ||||
|       /// <summary>Loads an assembly from a file system path</summary> | ||||
|       /// <param name="path">Path the assembly will be loaded from</param> | ||||
|       /// <returns>The loaded assembly</returns> | ||||
|       protected virtual Assembly LoadAssemblyFromFile(string path) { | ||||
|         return Assembly.LoadFile(path); | ||||
|       } | ||||
| 
 | ||||
|       /// <summary>Tries to loads an assembly from a file</summary> | ||||
|       /// <param name="path">Path to the file that is loaded as an assembly</param> | ||||
|       /// <param name="loadedAssembly"> | ||||
|       ///   Output parameter that receives the loaded assembly or null | ||||
|       /// </param> | ||||
|       /// <returns>True if the assembly was loaded successfully, otherwise false</returns> | ||||
|       public bool TryLoadFile(string path, out Assembly loadedAssembly) { | ||||
| 
 | ||||
|         // A lot of errors can occur when attempting to load an assembly... | ||||
|         try { | ||||
|           loadedAssembly = LoadAssemblyFromFile(path); | ||||
|           return true; | ||||
|         } | ||||
|         // File not found - Most likely a missing dependency of the assembly we | ||||
|         // attempted to load since the assembly itself has been found by the GetFiles() method | ||||
|         catch(DllNotFoundException) { | ||||
|           Trace.WriteLine( | ||||
|             "Assembly '" + path + "' or one of its dependencies is missing" | ||||
|           ); | ||||
|         } | ||||
|         // Unauthorized acccess - Either the assembly is not trusted because it contains | ||||
|         // code that imposes a security risk on the system or a user rights problem | ||||
|         catch(UnauthorizedAccessException) { | ||||
|           Trace.WriteLine( | ||||
|             "Not authorized to load assembly '" + path + "', " + | ||||
|             "possible rights problem" | ||||
|           ); | ||||
|         } | ||||
|         // Bad image format - This exception is often thrown when the assembly we | ||||
|         // attempted to load requires a different version of the .NET framework | ||||
|         catch(BadImageFormatException) { | ||||
|           Trace.WriteLine( | ||||
|             "'" + path + "' is not a .NET assembly, requires a different version " + | ||||
|             "of the .NET Runtime or does not support the current instruction set (x86/x64)" | ||||
|           ); | ||||
|         } | ||||
|         // Unknown error - Our last resort is to show a default error message | ||||
|         catch(Exception exception) { | ||||
|           Trace.WriteLine( | ||||
|             "Failed to load plugin assembly '" + path + "': " + exception.Message | ||||
|           ); | ||||
|         } | ||||
| 
 | ||||
|         loadedAssembly = null; | ||||
|         return false; | ||||
| 
 | ||||
|       } | ||||
| 
 | ||||
|       /// <summary>The only instance of the DefaultAssemblyLoader</summary> | ||||
|       public static readonly DefaultAssemblyLoader Instance = | ||||
|         new DefaultAssemblyLoader(); | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     #endregion // class DefaultAssemblyLoader | ||||
| 
 | ||||
|     /// <summary>Triggered whenever a new assembly is loaded into this repository</summary> | ||||
|     public event AssemblyLoadEventHandler AssemblyLoaded; | ||||
| 
 | ||||
|     /// <summary>Initializes a new instance of the plugin repository</summary> | ||||
|     public PluginRepository() { | ||||
|     public PluginRepository() : this(DefaultAssemblyLoader.Instance) { } | ||||
| 
 | ||||
|     /// <summary>Initializes a new instance of the plugin repository</summary> | ||||
|     /// <param name="loader"> | ||||
|     ///   Loader to use for loading assemblies into this repository | ||||
|     /// </param> | ||||
|     public PluginRepository(IAssemblyLoader loader) { | ||||
|       this.assemblies = new List<Assembly>(); | ||||
|       this.assemblyLoader = loader; | ||||
|     } | ||||
| 
 | ||||
|     /// <summary>Loads all plugins matching a wildcard specification</summary> | ||||
|  | @ -63,38 +146,9 @@ namespace Nuclex.Support.Plugins { | |||
|       string[] assemblyFiles = Directory.GetFiles(directory, search); | ||||
|       foreach(string assemblyFile in assemblyFiles) { | ||||
| 
 | ||||
|         // A lot of errors can occur when attempting to load an assembly... | ||||
|         try { | ||||
|           AddAssembly(Assembly.LoadFile(assemblyFile)); | ||||
|         } | ||||
|         // File not found - Most likely a missing dependency of the assembly we | ||||
|         // attempted to load since the assembly itself has been found by the GetFiles() method | ||||
|         catch(DllNotFoundException) { | ||||
|           Console.WriteLine( | ||||
|             "Assembly '" + assemblyFile + "' or one of its dependencies is missing" | ||||
|           ); | ||||
|         } | ||||
|         // Unauthorized acccess - Either the assembly is not trusted because it contains | ||||
|         // code that imposes a security risk on the system or a user rights problem | ||||
|         catch(UnauthorizedAccessException) { | ||||
|           Console.WriteLine( | ||||
|             "Not authorized to load assembly '" + assemblyFile + "', " + | ||||
|             "possible rights problem" | ||||
|           ); | ||||
|         } | ||||
|         // Bad image format - This exception is often thrown when the assembly we | ||||
|         // attempted to load requires a different version of the .NET framework | ||||
|         catch(BadImageFormatException) { | ||||
|           Console.WriteLine( | ||||
|             "'" + assemblyFile +"' is not a .NET assembly, requires a different version " + | ||||
|             "of the .NET Runtime or does not support the current instruction set (x86/x64)" | ||||
|           ); | ||||
|         } | ||||
|         // Unknown error - Our last resort is to show a default error message | ||||
|         catch(Exception exception) { | ||||
|           Console.WriteLine( | ||||
|             "Failed to load plugin assembly '" + assemblyFile + "': " + exception.Message | ||||
|           ); | ||||
|         Assembly loadedAssembly; | ||||
|         if(this.assemblyLoader.TryLoadFile(assemblyFile, out loadedAssembly)) { | ||||
|           AddAssembly(loadedAssembly); | ||||
|         } | ||||
| 
 | ||||
|       } | ||||
|  | @ -121,6 +175,8 @@ namespace Nuclex.Support.Plugins { | |||
| 
 | ||||
|     /// <summary>Loaded plugin assemblies</summary> | ||||
|     private List<Assembly> assemblies; | ||||
|     /// <summary>Takes care of loading assemblies for the repositories</summary> | ||||
|     private IAssemblyLoader assemblyLoader; | ||||
| 
 | ||||
|   } | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue