简体   繁体   中英

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

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?

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

How about loading 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" });
        }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM