Вопрос архитектуры плагина C # - PullRequest
5 голосов
/ 29 сентября 2010

Я работаю над приложением для мониторинга системы, похожим на Nagios в C #. У меня есть интерфейс плагина, определенный как:

public interface IPlugin
{
    PluginResult Execute();
}

Каждый плагин, в зависимости от его функциональности, будет иметь переменное количество аргументов. Например, пинг плагин может принимать имя хоста, количество пакетов, значение времени ожидания и т. Д. Я хочу, чтобы пользователь мог определять эти аргументы для каждой службы в моем пользовательском интерфейсе, но, очевидно, эти аргументы не будут известны до приложение обнаруживает, какие плагины доступны. Мне любопытно, как другие могут спроектировать плагин так, чтобы эти переменные аргументы могли быть обнаружены приложением.

Прямо сейчас, например, у меня есть пинг плагин:

public class PingPlugin : IPlugin
{
    private const string RESULT_MESSAGE = "Average ms: {0}; Packet loss: {1}";

    private string _hostname;
    private int _packets;
    private int _timeout;
    private int _warningTimeThreshold;
    private int _warningLossThreshold;
    private int _errorTimeThreshold;
    private int _errorLossThreshold;

    public PingPlugin(
        string hostname,
        int packets,
        int timeout,
        int warningTimeThreshold,
        int warningLossThreshold,
        int errorTimeThreshold,
        int errorLossThreshold)
    {
        _hostname = hostname;
        _packets = packets;
        _timeout = timeout;
        _warningTimeThreshold = warningTimeThreshold;
        _warningLossThreshold = warningLossThreshold;
        _errorTimeThreshold = errorTimeThreshold;
        _errorLossThreshold = errorLossThreshold;
    }

    public PluginResult Execute()
    {
        // execute the plugin
    }
}

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

Ответы [ 5 ]

18 голосов
/ 29 сентября 2010

Рассматривали ли вы возможность использования Managed Extensibility Framework ?

4 голосов
/ 29 сентября 2010

Вместо того, чтобы конструктор плагинов определял параметры, вы могли бы рассмотреть что-то вроде этого:

public interface IPlugin
{
    PluginResult Execute(Object parameters);
}

public class PingParameters
{
    //Various parameters here, including [Description] and [DisplayName] attributes if you wish
}

public class ParametersTypeAttribute : Attribute
{
    public Type Type { get; private set; }

    public ParametersTypeAttribute(Type type)
    {
        Type = type;
    }
}

[ParametersType(typeof(PingParameters))]
public class PingPlugin : IPlugin
{
    public PluginResult Execute(Object parameters)
    {
        return Execute((PingParameters) parameters);
    }

    private PluginResult Execute(PingParameters parameters)
    {
        //Your execution code here
    }
}

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

1 голос
/ 29 сентября 2010

Вы можете применить атрибут [DefaultValue] к параметрам.

В C # for вы можете использовать новый синтаксис для этого: int warningLossThreshold = 30,

0 голосов
/ 29 сентября 2010

Я не смотрел на MEF (сделаю сейчас).

У меня была проблема, почти идентичная вашей, я решил ее с помощью Attributes.
У меня есть пользовательский интерфейс, который (вызывает BL, который) использует отражение, чтобы показать все доступные «услуги» (не более, чем соответствующим образом оформленные классы).

Когда пользователь выбирает «сервис», дополнительные атрибуты управляют пользовательским интерфейсом. Атрибут «схема» довольно прост и допускает любое количество параметров с любым именем. Вводя константы (с определением атрибута), вы можете стандартизировать общие вещи, такие как «имя», чтобы ваши сервисы были согласованными.

Все данные затем сохраняются в таблице пар ключ-значение.

Самое замечательное в этом то, что вы можете просто выгружать новые / модифицированные "сервисные" сборки в bin dir - никакой дополнительной работы не требуется. Единственная зависимость - это сборка определений атрибутов - так что придерживайтесь этого.

Исходный код на CodePlex , если вы хотите "украсть" некоторые:)

0 голосов
/ 29 сентября 2010

Я также проголосовал +1 за ответ MEF, он решит многие ваши проблемы.

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

Один из возможных вариантов может быть следующим: иметь интерфейс IPluginProvider, который может обнаружить ваше приложение.Это должен иметь конструктор без параметров, чтобы вы могли легко new создать экземпляр.Затем он должен иметь методы, которые возвращают все необходимые метаданные (например, «красивые имена» для параметров, которые требуются, какие разумные значения по умолчанию и т. Д.).Затем он должен включать метод CreateInstance, который принимает фактические параметры как IDictionary<string,object> и возвращает фактический IPlugin экземпляр.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...