проблема с настройкой модульного приложения - PullRequest
0 голосов
/ 23 октября 2019

Недавно я нашел хороший пример для настройки модульного приложения и попытался адаптировать его к своим личным требованиям. Мое вдохновение пришло от этого вопроса здесь, на Stackoverflow:

Используя MEF с C #, как я могу вызывать методы на хосте из плагина?

Прежде всего ясам попробовал код из этого примера и все заработало. Я попытался изменить его для обработки нескольких плагинов, и это было успешно. Поэтому я попытался использовать этот код в своем собственном проекте, и вот тут-то и начались проблемы ...

Вот требования к моему проекту:

  • динамическая обработка нескольких плагинов,Чтобы установить новые плагины, просто поместите их библиотеку .dll в указанную папку.

  • запуск отдельных плагинов должен быть динамическим, а также. Они активируются по выбору пользователя

  • двунаправленный обмен данными и вызов методов: основное приложение должно иметь возможность вызывать определенные методы каждого плагина, а плагины должны иметь возможность вызыватьметод основного приложения для обратной связи в реальном времени о статусе плагина.

Вот фрагменты кода того, что я создал до сих пор (названия на немецком языке):

Интерфейс Библиотека:

using System;
using System.ComponentModel.Composition;

using Siemens.Engineering;

namespace Interfaces
{
    [InheritedExport]
    public interface IPlugin
    {
        void MeldungSenden();
        void Programm(TiaPortal TIAInstanz, Project TIAProjekt);
        string Name();
    }
    [InheritedExport]
    public interface IMain
    {
        void MeldungEmpfangen(string[] Meldung, EventArgs e);
    }
}

Один пример базового Плагин для целей тестирования:

   using System;
    using System.ComponentModel.Composition;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Reflection;
    using System.Windows.Forms;

    using Siemens.Engineering;

    namespace FER_ServiceTool_Testmodul
    {
        [Export]
        public class Program : Interfaces.IPlugin
        {
            static string[] TextMeldung = new string[8];

            [Import(typeof(Interfaces.IMain))]
            public Interfaces.IMain Hauptprogramm;

            public string Name()
            {
                return "Testmodul 1";
            }
            public void MeldungSenden()
            {
                Hauptprogramm.MeldungEmpfangen(TextMeldung, null);
            }
            public void Programm(TiaPortal TIAInstanz, Project TIAProjekt)
            {
                TextMeldung[0] = "Ich bin eine Testmeldung";
                TextMeldung[1] = "Testmodul 1";
                TextMeldung[2] = "Testmeldung";
                TextMeldung[3] = "Bausteine/FB";
                TextMeldung[4] = "SPS_1";
                TextMeldung[5] = "Generator";
                TextMeldung[6] = "Programmbausteine/Maschinenhalle/Generator";
                TextMeldung[7] = "Hier könnte ihre Korrektur stehen";
                MeldungSenden();
            }
        }
}

Main *Приложение 1038 * имеет 2 класса, которые используются для плагина System:

Класс: Mainform: Form, Interfaces.IMain полностью настроен для [Export], поэтому плагины могут вызывать методы этого класса при необходимости. Класс имеет метод:

public void MeldungEmpfangen(string[] MeldungInput, EventArgs e)
        {
            MessageBox.Show("Empfange Meldung", "", MessageBoxButtons.OK);
            EventHandler EintragenEvent = MeldungEintragen;
            if(EintragenEvent != null)
            {
                MeldungText = MeldungInput;
                EintragenEvent(this,e);
            }
        }

Этот метод получает обратную связь от плагинов и запускает событие для включения списка строк в DataGridView, расположенный в основной форме. Таким образом, я избегаю межпотоковой обработки управления

Второй класс основного приложения собирает файлы плагина .dll из указанной папки:

public class ServiceTool                            
    {
        private CompositionContainer _container;
        [ImportMany(typeof(Interfaces.IPlugin))]
        public List<Interfaces.IPlugin> Liste = new List<Interfaces.IPlugin>();

        //const string ProfilPfad = @"D:\\Automation\\TIA\\FER-ServiceTool\\PlugIns";

        public ServiceTool()
        {
            ModuleSuchen();
        }

теперь япопробовал 2 РАЗНЫЕ реализации для метода "ModuleSuchen":

первая идет в соответствии с примером, который я перечислил в верхней части моего вопроса

void ModuleSuchen()
        {
            var catalog = new AggregateCatalog();
            catalog.Catalogs.Add(new DirectoryCatalog("D:\\Automation\\TIA\\FER-ServiceTool\\PlugIns"));
            catalog.Catalogs.Add(new AssemblyCatalog(System.Reflection.Assembly.GetExecutingAssembly()));
            _container = new CompositionContainer(catalog);
            try
            {
                this._container.ComposeParts(this);
            }
            catch (CompositionException compositionException)
            {
                Console.WriteLine(compositionException.ToString());
            }
        }

Используя эту версию, мое приложение не можетчтобы загрузить любые файлы плагина .dll, и я понятия не имею, почему. Поэтому я попробовал другую реализацию:

void ModuleSuchen()                                 
        {
            foreach(string Datei in Directory.GetFiles(ProfilPfad, "*.dll", SearchOption.TopDirectoryOnly))
            {
                try
                {
                    Assembly.LoadFile(Datei);
                }
                catch
                {
                    MessageBox.Show("Fehler", "", MessageBoxButtons.OK);
                }
            }
            Type InterfaceTyp   = typeof(Interfaces.IPlugin);
            try
            {   
                Type[] Typen        = AppDomain.CurrentDomain.GetAssemblies()
                    .SelectMany(a => a.GetTypes())
                    .Where(p => InterfaceTyp.IsAssignableFrom(p) && p.IsClass)
                    .ToArray();

                foreach(Type Typ in Typen)
                {
                    Liste.Add((Interfaces.IPlugin)Activator.CreateInstance(Typ));
                }
            }
            catch(Exception e)
            {
                MessageBox.Show(""+e.ToString(), "", MessageBoxButtons.OK);
            }
        }

Используя этот метод, плагины загружаются правильно, но они не "видят" основное приложение. Поэтому я получаю исключение NullReferenceException в своем плагине, когда я пытаюсь использовать метод «MeldungSenden ()». Объект «Hauptprogramm» всегда равен нулю, в то время как он должен содержать что-то вроде «Mainform».

Я надеюсь, что вы можете сказать мне, где я допустил ошибку. Если вам нужна дополнительная информация, не стесняйтесь спрашивать.

Спасибо за терпение прочитать мой длинный вопрос

...