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
|
@ -123,16 +123,14 @@
|
||||||
<Compile Include="Source\PathHelper.Test.cs">
|
<Compile Include="Source\PathHelper.Test.cs">
|
||||||
<DependentUpon>PathHelper.cs</DependentUpon>
|
<DependentUpon>PathHelper.cs</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Source\Plugins\AbstractFactory.cs" />
|
<Compile Include="Source\Plugins\IAbstractFactory.cs" />
|
||||||
<Compile Include="Source\Plugins\AbstractFactory.Test.cs">
|
|
||||||
<DependentUpon>AbstractFactory.cs</DependentUpon>
|
|
||||||
</Compile>
|
|
||||||
<Compile Include="Source\Plugins\Employer.Test.cs">
|
<Compile Include="Source\Plugins\Employer.Test.cs">
|
||||||
<DependentUpon>Employer.cs</DependentUpon>
|
<DependentUpon>Employer.cs</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Source\Plugins\FactoryEmployer.Test.cs">
|
<Compile Include="Source\Plugins\FactoryEmployer.Test.cs">
|
||||||
<DependentUpon>FactoryEmployer.cs</DependentUpon>
|
<DependentUpon>FactoryEmployer.cs</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="Source\Plugins\IAssemblyLoader.cs" />
|
||||||
<Compile Include="Source\Plugins\InstanceEmployer.Test.cs">
|
<Compile Include="Source\Plugins\InstanceEmployer.Test.cs">
|
||||||
<DependentUpon>InstanceEmployer.cs</DependentUpon>
|
<DependentUpon>InstanceEmployer.cs</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
|
|
@ -19,21 +19,22 @@ License along with this library
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
#if UNITTEST
|
|
||||||
|
|
||||||
using NUnit.Framework;
|
|
||||||
using NUnit.Framework.SyntaxHelpers;
|
|
||||||
|
|
||||||
namespace Nuclex.Support.Plugins {
|
namespace Nuclex.Support.Plugins {
|
||||||
|
|
||||||
/// <summary>Unit Test for the abstract factory interface</summary>
|
/// <summary>Interface for an assembly loading helper</summary>
|
||||||
[TestFixture]
|
public interface IAssemblyLoader {
|
||||||
public class AbtractFactoryTest {
|
|
||||||
|
/// <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
|
} // namespace Nuclex.Support.Plugins
|
||||||
|
|
||||||
#endif // UNITTEST
|
|
|
@ -20,6 +20,7 @@ License along with this library
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
#if UNITTEST
|
#if UNITTEST
|
||||||
|
|
||||||
|
@ -29,8 +30,133 @@ using NUnit.Framework.SyntaxHelpers;
|
||||||
namespace Nuclex.Support.Plugins {
|
namespace Nuclex.Support.Plugins {
|
||||||
|
|
||||||
/// <summary>Unit Test for the plugin host class</summary>
|
/// <summary>Unit Test for the plugin host class</summary>
|
||||||
[TestFixture]
|
[TestFixture, NoPlugin] // NoPlugin is used in one of the unit tests
|
||||||
public class PluginHostTest {
|
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
|
} // namespace Nuclex.Support.Plugins
|
||||||
|
|
|
@ -19,6 +19,7 @@ License along with this library
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
namespace Nuclex.Support.Plugins {
|
namespace Nuclex.Support.Plugins {
|
||||||
|
@ -83,10 +84,8 @@ namespace Nuclex.Support.Plugins {
|
||||||
|
|
||||||
// Types that have been tagged with the [NoPlugin] attribute will be ignored
|
// Types that have been tagged with the [NoPlugin] attribute will be ignored
|
||||||
object[] attributes = type.GetCustomAttributes(true);
|
object[] attributes = type.GetCustomAttributes(true);
|
||||||
for(int index = 0; index < attributes.Length; ++index) {
|
if(containsNoPluginAttribute(attributes)) {
|
||||||
if(attributes[index] is NoPluginAttribute) {
|
continue;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Type seems to be acceptable, assess and possibly employ it
|
// Type seems to be acceptable, assess and possibly employ it
|
||||||
|
@ -96,14 +95,26 @@ namespace Nuclex.Support.Plugins {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(Exception exception) {
|
catch(Exception exception) {
|
||||||
System.Console.WriteLine(
|
Trace.WriteLine("Could not employ " + type.ToString() + ": " + exception.Message);
|
||||||
"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>
|
/// <summary>Employs and manages types in the loaded plugin assemblies</summary>
|
||||||
private Employer employer;
|
private Employer employer;
|
||||||
/// <summary>Repository containing all plugins loaded, shared with other hosts</summary>
|
/// <summary>Repository containing all plugins loaded, shared with other hosts</summary>
|
||||||
|
|
|
@ -19,6 +19,7 @@ License along with this library
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
|
@ -53,6 +54,40 @@ namespace Nuclex.Support.Plugins {
|
||||||
|
|
||||||
#endregion // interface IProgressTrackerSubscriber
|
#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>
|
/// <summary>
|
||||||
/// Tests whether the default constructor of the plugin repository class works
|
/// Tests whether the default constructor of the plugin repository class works
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -81,6 +116,8 @@ namespace Nuclex.Support.Plugins {
|
||||||
|
|
||||||
Assembly self = Assembly.GetAssembly(GetType());
|
Assembly self = Assembly.GetAssembly(GetType());
|
||||||
testRepository.AddFiles(self.Location);
|
testRepository.AddFiles(self.Location);
|
||||||
|
|
||||||
|
Assert.AreEqual(1, testRepository.LoadedAssemblies.Count);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -118,6 +155,50 @@ namespace Nuclex.Support.Plugins {
|
||||||
mockery.VerifyAllExpectationsHaveBeenMet();
|
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>
|
/// <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="mockery">Mockery to create an event subscriber in</param>
|
||||||
/// <param name="repository">Repository to subscribe the mocked subscriber to</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;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Reflection;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
namespace Nuclex.Support.Plugins {
|
namespace Nuclex.Support.Plugins {
|
||||||
|
|
||||||
|
@ -33,12 +34,94 @@ namespace Nuclex.Support.Plugins {
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public class PluginRepository {
|
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>
|
/// <summary>Triggered whenever a new assembly is loaded into this repository</summary>
|
||||||
public event AssemblyLoadEventHandler AssemblyLoaded;
|
public event AssemblyLoadEventHandler AssemblyLoaded;
|
||||||
|
|
||||||
/// <summary>Initializes a new instance of the plugin repository</summary>
|
/// <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.assemblies = new List<Assembly>();
|
||||||
|
this.assemblyLoader = loader;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Loads all plugins matching a wildcard specification</summary>
|
/// <summary>Loads all plugins matching a wildcard specification</summary>
|
||||||
|
@ -63,38 +146,9 @@ namespace Nuclex.Support.Plugins {
|
||||||
string[] assemblyFiles = Directory.GetFiles(directory, search);
|
string[] assemblyFiles = Directory.GetFiles(directory, search);
|
||||||
foreach(string assemblyFile in assemblyFiles) {
|
foreach(string assemblyFile in assemblyFiles) {
|
||||||
|
|
||||||
// A lot of errors can occur when attempting to load an assembly...
|
Assembly loadedAssembly;
|
||||||
try {
|
if(this.assemblyLoader.TryLoadFile(assemblyFile, out loadedAssembly)) {
|
||||||
AddAssembly(Assembly.LoadFile(assemblyFile));
|
AddAssembly(loadedAssembly);
|
||||||
}
|
|
||||||
// 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
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -121,6 +175,8 @@ namespace Nuclex.Support.Plugins {
|
||||||
|
|
||||||
/// <summary>Loaded plugin assemblies</summary>
|
/// <summary>Loaded plugin assemblies</summary>
|
||||||
private List<Assembly> assemblies;
|
private List<Assembly> assemblies;
|
||||||
|
/// <summary>Takes care of loading assemblies for the repositories</summary>
|
||||||
|
private IAssemblyLoader assemblyLoader;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user