D
D
Dmitry2020-02-18 15:28:22
C++ / C#
Dmitry, 2020-02-18 15:28:22

How to solve the problem of dynamically connecting assemblies of an extensible application?

Good afternoon. Faced the following problem:
I wanted to make an application that checks the folder for plug-in assemblies and loads them dynamically. When pluggable assemblies do not contain references to other assemblies, everything works fine. But when assemblies refer to methods of other local assemblies, an exception is thrown that the assembly was not found, which is logical, since the assembly is not loaded into the domain. It’s just that commercial applications (for example, Revit) calmly process such references, it’s enough to implement the necessary interfaces in the main assembly, and if my assembly contains references to other assemblies during the execution of the interface method, then they don’t have any exceptions and the methods are called. The question is how can this problem be solved and how do commercial applications solve this problem?
In more detail, an explanatory example:
The code of the main application in the Modules folder which contains the StarterLib.dll and HelloWorld.dll assemblies:

class Program
    {
        static void Main(string[] args)
        {
            LoadAssembliesModules();
            Console.ReadLine();
        }
        private static void LoadAssembliesModules()
        {
            string modulespath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "//Modules";

            var AddInAssemblies = Directory.EnumerateFiles(modulespath, "*.dll");
           
            var AddInTypes = from file in AddInAssemblies
                             let assembly = Assembly.LoadFile(file)
                             from t in assembly.ExportedTypes // Открыто экспортируемые типы
                                                              // Тип может использоваться, если это класс, реализующий IStart
                             where t.IsClass &&
                                         typeof(IStart).GetTypeInfo().IsAssignableFrom(t.GetTypeInfo())
                             select t;
            
            foreach (Type t in AddInTypes)
            {
                    IStart ai = (IStart)Activator.CreateInstance(t);

                    if (ai != null)
                    {
                        ai.Start();
                    }                
            }
        }
    }

StarterLib.dll assembly code referring to HelloWorld.dll:
public class Class1: IStart
    {
        public void Start()
        {
            Console.WriteLine("Hello");
            //Не работает если убрать комментарии ниже:
            //Hello h = new Hello();
            //h.StartHello();
        }       
    }

HelloWorld.dll assembly code:
public class Hello
    {
        public void StartHello()
        {
            System.Windows.Forms.MessageBox.Show("Hello World");
        }        
    }

Answer the question

In order to leave comments, you need to log in

2 answer(s)
P
Peter, 2020-02-18
@Ksarrik

Everything is simple. Implement your own code
AppDomain.AssemblyResolve += OnAssemblyResolve;
And in OnAssemblyResolve load the requested assemblies into the domain

F
freeExec, 2020-02-18
@freeExec

You call the method assembly.GetReferencedAssemblies();and get the assemblies it depends on. And so recursively through all the assemblies, get their pool and load them.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question