How to create dynamic instance of assembly ( C# ) and loading the dependencies of instance assembly dynamically as well?

StackOverflow https://stackoverflow.com/questions/22824552

Question

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:

enter image description here

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?

Was it helpful?

Solution

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();
}

OTHER TIPS

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" });
        }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top