I am working on an application with two supporting DLLs in the Project. ClassLibrary1.dll
and ClassLibrary2.dll
. The ClassLibrary2.dll is optional and only used by the ClassLibrary1.dll
. The application has a feature to import the DLL explicitly. Everything worked fine if I import both DLLs into the application.
The problem arises when I don’t import the optional ClassLibrary2.dll.
Here on application start, I am checking whether assembly exists or not:
var assemblyName = "ClassLibrary2.dll, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null";
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
var assembly = (from a in assemblies
where a.FullName == assemblyName
select a).SingleOrDefault();
// this IsClassLibrary2Exists property become true when the DLL exists
if (assembly != null)
{
Props.IsClassLibrary2Exists = true;
}
Here is How I am calling the ClassLibrary2 method in ClassLibrary1
if(Props.IsClassLibrary2Exists){
ClassLibrary2.SpecialProduct.GetSpecialProduct(Id);
}
I am getting an error when the assembly does not exist:
"System.IO.FileNotFoundException: ‘Could not load file or assembly ‘ClassLibrary2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null’ or one of its dependencies. The system cannot find the file specified.’"
2
Answers
To have any success in preventing one assembly to require the other one you need all access to the "assembly 2" to be done via methods that are not executed. Protecting access with
if
is not enough because whole method need to be JITed first and that requires loading the other assembly.What likely would work:
Note that it is extremely easy to use "the other library" in a way that is hard/impossible to fix at run-time – static properties/constructors can be called at any time and hence referencing anything from the other library there will fail, having fields/properties/method parameters/return to use types from the other library would fail even via reflection… and like many other cases.
If possible prefer to load the assembly dynamically and have it implement shared interfaces so you can limit reflection to instantiation part, but use those classes via strongly typed interfaces.
I agree with the comment by Dai that the underlying issue is that
ClassLibrary1
has a hardcoded dependency onClassLibrary2
so the matter falls to how this can be decoupled.One approach that has worked for me is to have an
Interface
class library consisting only of plugin interfaces that the application may attempt to use (but which, at the same time, might not have instances attached). It will be referenced by plugin servers and clients alike.Interface
class libraryClassLibrary1
The
SpecialProduct
member is decoupled fromClassLibrary2
because it’s an interface not a class.ClassLibrary2
Test (proof of concept using console app)
Available plugins are located in the
Plugins
subfolder of the application’s run directory.ClassLibrary2
is not initially referenced or loaded.