@Ksarrik

Как решить проблему динамического подключения сборок расширяемого приложения?

Добрый день. Столкнулся с следующей проблемой:
Хотел сделать приложение, которое проверяет папку на наличие сборок-подключаемых модулей и динамически их подгружает. Когда подключаемые сборки не содержать ссылок на другие сборки, все работает нормально. Но когда сборки ссылаются на методы других локальных сборок выскакивает исключение, что сборка не найдена, что логично, поскольку сборка не загружена в домен. Просто коммерческие приложения ( например Revit) спокойно обрабатывают такие ссылки, достаточно в основной сборке реализовать необходимые интерфейсы, и если моя сборка содержит ссылки на другие сборки в процессе выполнения метода интерфейса, то у них никаких исключений не возникает и методы вызываются. Вопрос как можно решить данную проблему и как решают эту проблему коммерческие приложения?
Подробнее, поясняющий пример:
Код основного приложения в папке Modules которого содержатся сборки StarterLib.dll и HelloWorld.dll:
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 ссылающейся на HelloWorld.dll:
public class Class1: IStart
    {
        public void Start()
        {
            Console.WriteLine("Hello");
            //Не работает если убрать комментарии ниже:
            //Hello h = new Hello();
            //h.StartHello();
        }       
    }

Код сборки HelloWorld.dll:
public class Hello
    {
        public void StartHello()
        {
            System.Windows.Forms.MessageBox.Show("Hello World");
        }        
    }
  • Вопрос задан
  • 86 просмотров
Решения вопроса 2
petermzg
@petermzg
Самый лучший программист
Все просто. Реализуйте у себя код
AppDomain.AssemblyResolve += OnAssemblyResolve;
И в OnAssemblyResolve подгружайте в домен запрашиваемые сборки
Ответ написан
Комментировать
@Ksarrik Автор вопроса
Вроде бы нашел решение, оказалось на удивление простым: для автоматического обнаружения сборок достаточно было в config основного приложения добавить папку в которой искать необходимые сборки.
А именно:
<runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <probing privatePath="Modules"/>
    </assemblyBinding>
  </runtime>
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
freeExec
@freeExec
Участник OpenStreetMap
Вызываете метод assembly.GetReferencedAssemblies(); и получаете сборки от которых он зависит. И так рекурсивно по всем сборкам, получаете их пул и грузите их.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы