Reputation: 1344
I am loading CalculatorDependency.dll to AppDomain which is dependency of Add class (implementation of IAdd from Calculator.Interface.dll) from Calculator.dll.
The thing is I don't want to put implementer dll (Calculator.dll) and it's dependency dll (CalculatorDependency.dll) at executing assembly location or in GAC. I want to load it dynamically from given locations respectively. So I am loading Interface implementer dll and it's dependency to AppDomain first to create an instance.
Here is my code !!
static void Main(string[] args)
{
// Loading dependency dll into memory
var dependency = string.Concat(Directory.GetCurrentDirectory(), @"\Implementations\CalculatorDependency.dll");
var dependencyBytes = File.ReadAllBytes(dependency);
// Loading implementer dll into memory
var implementor = string.Concat(Directory.GetCurrentDirectory(), @"\Implementations\Calculator.dll");
var implementorBytes = File.ReadAllBytes(implementor);
// Adding dependency dll to AppDomain (CalculatorDependency.dll)
AppDomain.CurrentDomain.Load(dependencyBytes);
// Adding implementor dll to AppDomain (Calculator.dll)
AppDomain.CurrentDomain.Load(implementorBytes);
// Checking loaded assemblies and both above assemblies are exist in output
var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies().ToList();
foreach (var a in loadedAssemblies)
{
Console.WriteLine(a.GetName().Name);
}
// Calling function to get an instance of IAdd as Calculator.Add class from Calculator.dll
var obj = GetObject<IAdd>();
// Object was resolved successfully but was failed at this line as SumNew is a dependent function on CalculatorDependency.dll
Console.WriteLine(obj.SumNew(2, 2));
}
public static T GetObject<T>()
{
var t = typeof(T);
var objects = (
from assembly in AppDomain.CurrentDomain.GetAssemblies()
from type in assembly.GetExportedTypes()
where typeof(T).IsAssignableFrom(type) && !type.FullName.Equals(t.FullName)
select (T)Activator.CreateInstance(type)
).ToArray();
return objects.FirstOrDefault();
}
Error:
An unhandled exception of type 'System.IO.FileNotFoundException' occurred in TestConsole.exe
Additional information: Could not load file or assembly 'CalculatorDependency, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.
Console output of loaded assemblies:
Can someone please help me out to find out what is wrong here? And even if CalculatorDependency.dll is loaded why it is still looking for a file to load again?
Upvotes: 1
Views: 2861
Reputation: 87
It is a good idea to load the file in Memory stream and then using it.
using (FileStream file = new FileStream(@"c:\temp\TestAccountScrubbing.dll", FileMode.Open, FileAccess.Read))
{
byte[] bytes = new byte[file.Length];
file.Read(bytes, 0, (int)file.Length);
ms.Write(bytes, 0, (int)file.Length);
}
ms.Seek(0, SeekOrigin.Begin);
Assembly assembly = Assembly.Load(ms.ToArray());
Type type = assembly.GetType("TestAccountScrubbing.AccountScubbing");
object obj = Activator.CreateInstance(type);
var returnValue =type.InvokeMember("Main",
BindingFlags.Default | BindingFlags.InvokeMethod,
null,
obj,
new object[] { "Hello World" });
}
Upvotes: 0
Reputation: 1344
Finally I found solution for my problem.
This is what worked for me. Perfect and what I was looking for !! :)
static void Main(string[] args)
{
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
var implementor = string.Concat(Directory.GetCurrentDirectory(), @"\Implementations\Calculator.dll");
var implementorBytes = File.ReadAllBytes(implementor);
AppDomain.CurrentDomain.Load(implementorBytes);
Console.WriteLine(GetObject<IAdd>().SumNew(2, 2));
Console.WriteLine(GetObject<IAdd>().SumNew(2, 5));
}
static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
var dependencyResolverBaseDirectory = string.Concat(Directory.GetCurrentDirectory(), @"\Implementations");
return Directory.GetFiles(dependencyResolverBaseDirectory, "*.dll")
.Select(Assembly.LoadFile)
.FirstOrDefault(assembly => string.Compare(args.Name, assembly.FullName, StringComparison.CurrentCultureIgnoreCase) == 0);
}
public static T GetObject<T>()
{
var t = typeof(T);
var objects = (
from assembly in AppDomain.CurrentDomain.GetAssemblies()
from type in assembly.GetExportedTypes()
where typeof(T).IsAssignableFrom(type) && (string.Compare(type.FullName, t.FullName, StringComparison.CurrentCultureIgnoreCase) != 0)
select (T)Activator.CreateInstance(type)
).ToList();
return objects.FirstOrDefault();
}
Upvotes: 2