У меня есть приложение базы данных, которое настраивается пользователем - некоторые из этих параметров выбирают из разных внешних систем плагинов.
У меня есть базовый тип плагина, моя схема базы данных имеет тот же тип записи плагина с теми же полями. У меня есть PlugingMananger
для загрузки плагинов (через контейнер IoC) при запуске приложения и привязки их к базе данных (по существу копирует поля из плагина на диске в базу данных).
public interface IPlugin
{
Guid Id{ get; }
Version Version { get; }
string Name { get; }
string Description { get; }
}
Затем можно загрузить плагины с помощью PlugingMananger.GetPlugin(Guid pluginId, Guid userId)
, где идентификатор пользователя - это имя одного из нескольких пользователей, для которого может быть вызвано действие плагина.
Приложением заранее объявлено множество известных интерфейсов, каждое из которых связано с определенной функцией (форматирование, внешние данные, отправитель данных и т.д.), если плагин реализует интерфейс службы, который неизвестен, тогда он будет проигнорирован:
public interface IAccountsPlugin : IPlugin
{
IEnumerable<SyncDto> GetData();
bool Init();
bool Shutdown();
}
Плагины могут также иметь атрибуты параметров PluginSettingAttribute
, определенные для каждого пользователя в многопользовательской системе, - эти свойства устанавливаются, когда плагин извлекается для определенного пользователя, и PluginPropertyAttribute
для свойств, которые являются общими для всех пользователей и только для чтения, установленным плагином один раз, когда плагин зарегистрирован при запуске приложения.
public class ExternalDataConnector : IAccountsPlugin
{
public IEnumerable<AccountSyncDto> GetData() { return null; }
public void Init() { }
public void Shutdown() { }
private string ExternalSystemUsername;
// PluginSettingAttribute will create a row in the settings table, settingId
// will be set to provided constructor parameter. this field will be written to
// when a plugin is retrieved by the plugin manager with the value for the
// requesting user that was retrieved from the database.
[PluginSetting("ExternalSystemUsernameSettingName")]
public string ExternalSystemUsername
{
get { return ExternalSystemUsername }
set { ExternalSystemUsername = value; }
}
// PluginPropertyAttribute will create a row in the attributes table common for all users
[PluginProperty("ShortCodeName")]
public string ShortCode
{
get { return "externaldata"; }
}
public Version PluginVersion
{
get { return new Version(1, 0, 0, 0); }
}
public string PluginName
{
get { return "Data connector"; }
}
public string PluginDescription
{
get { return "Connector for collecting data"; }
}
}
Вот мои вопросы и области, на которые я ищу руководство:
-
С приведенной выше абстракцией связывания плагинов в контейнере IoC с базой данных пользователь может выбрать поле базы данных
Customer.ExternalAccountsPlugin = idOfExternalPlugin
. Это тяжело - есть ли более простой способ достижения другими системами (у SharePoint, например, есть много плагинов, на которые ссылается пользовательская база данных)? -
Мое приложение диктует во время компиляции интерфейсы, которые он поддерживает и игнорирует все остальные. Я видел, что некоторые системы утверждают, что они полностью расширяемы с помощью открытых плагинов, которые, как я полагаю, означают множество свободно типизированных интерфейсов и кастинг, есть ли на полпути между двумя параметрами, позволяющими выпускать будущие обновления без повторной компиляции, но при этом использовать конкретные интерфейсы?
-
Мои плагины могут содержать метаданные (PluginProperty или PluginSetting), и я не уверен, что это лучшее место для хранения этого файла, либо в таблице метаданных плагина (сделайте запросы linq более сложными), либо прямо в строке записи базы данных плагина ( easy linq queries
PluginManager.GetPluginsOfType<IAccounts>.Where(x => x.ShortCode = "externaldata").FirstOrDefault();
, который используется как лучшая практика? -
Поскольку возможности и интерфейсы плагинов сильно зависят от схемы базы данных, каков рекомендуемый способ, я могу ограничить плагин для использования с конкретной ревизией схемы? Могу ли я сохранить эту ревизию схемы как одну строку в таблице настроек в базе данных и обновить ее вручную после каждой версии? Будет ли плагин поддерживать максимальную версию схемы или приложение будет поддерживать список известных версий плагинов?