Страница 2 из 4 Шаг 1. Создание простого текстового редактора Я не буду надоедать вам с деталями. Вы все найдете в исходном коде: это всего лишь простая форма, показывающая кусок текста. С этого момента я предполагаю, что вы уже создали простое приложение. Шаг 2. Создание подключаемого SDK Теперь, когда у вас есть приложение, вы захотите, чтобы оно могло обмениваться информацией с внешним подключаемым модулем. Как это сделать? Решение в том, чтобы сориентировать работу приложения на опубликованный интерфейс, набор общих членов и методов, которые будут реализовываться всеми специальными подключаемыми модулями. Я назову этот интерфейс IPlugin. С этих пор любой разработчик, который захочет создать подключаемый модуль для вашего приложения, должен будет реализовать этот интерфейс. Он будет располагаться в общей библиотеке, которую будут использовать и ваше приложение, и любой специальный подключаемый модуль. Чтобы описать этот интерфейс, вам нужны просто некоторые данные о вашем простом подключаемом модуле: его имя и метод, который будет давать модулю указания осуществлять универсальные действия на основании данных вашего приложения. public interface IPlugin { string Name{get;} void PerformAction(IPluginContext context); } Код прост, но зачем передавать интерфейс IPluginContext в PerformAction? Причина, по которой вы посылаете интерфейс, а не просто строку — обеспечение большей гибкости в отношении того, какой объект вы сможете посылать. В настоящее время, интерфейс очень прост: public interface IPluginContext { string CurrentDocumentText{get;set;} } Теперь все, что вам надо сделать — реализовать этот интерфейс в одном или более объектов и отправить их в любой подключаемый модуль для получения результата. В будущем это позволит вам изменять строку не только текстового окна, но любого объекта. Шаг 3. Создание вашего специального подключаемого модуля Все, что вам сейчас надо сделать: - Создать отдельный объект библиотеки классов. - Создать класс, который реализовывает интерфейс IPlugin. - Откомпилировать этот класс и поместить его в ту же папку, к которой находится главное приложение. public class EmailPlugin:IPlugin { public EmailPlugin() { } public void PerformAction(IPluginContext context) { context.CurrentDocumentText= ParseEmails(context.CurrentDocumentText); }
public string Name { get { return "Email Parsing Plugin"; } }
private string ParseEmails(string text) { const string emailPattern= @"\w+@\w+\.\w+((\.\w+)*)?"; MatchCollection emails = Regex.Matches(text,emailPattern, RegexOptions.IgnoreCase); StringBuilder emailString = new StringBuilder(); foreach(Match email in emails) emailString.Append(email.Value + Environment.NewLine);
return emailString.ToString(); } } Шаг 4. Заставьте ваше приложение знать о новом подключаемом модуле Когда вы скомпилировали ваш подключаемый модуль, как приложение узнает о его существовании? Решение простое: - Создайте файл конфигурации приложения. - Создайте секцию в файле конфигурации, в которой перечислены все существующие подключаемые модули. - Создайте синтаксический анализатор для этой секции файла конфигурации. Чтобы завершить первый шаг, просто добавьте XML-файл в главное приложение. Назовите этот файл App.Config. В этом случае при каждой сборке вашего приложения Microsoft® Visual Studio .NET автоматически будет копировать этот файл в выходную папку и переименовывать его в <yourApp>.Config, избавляя вас от хлопот. Теперь разработчик подключаемого модуля должен иметь возможность легко добавить данные в файл конфигурации, чтобы опубликовать все созданные подключаемые модули. Здесь показано, как должен выглядеть файл конфигурации: <configuration> <configSections> <section name="plugins" type="Royo.PluggableApp.PluginSectionHandler, PluggableApp" /> </configSections> <plugins> <plugin type="Royo.Plugins.Custom.EmailPlugin, CustomPlugin" /> </plugins> </configuration>
Обратите внимание на тэг configSections. Он сообщает настройкам конфигурации приложения, что у вас в этом файле конфигурации есть секция подключаемых модулей, и что у вас есть синтаксический анализатор для этой секции. Он находится в классе Royo.PluggableApp.PluginSectionHandler, который располагается в сборке PluggableApp. Ниже я покажу вам код этого класса. Далее, у вас есть секция подключаемых модулей файла конфигурации, в которой перечислены для каждого подключаемого модуля имя класса и имя сборки, в которых он находится. Вы будете использовать эту информацию при создании экземпляров подключаемого модуля позже. Закончив файл конфигурации, вы завершаете один из этапов этого цикла. Подключаемый модуль готов к использованию, и сообщил о своем существовании во все необходимые каналы. Все, что вам осталось теперь сделать — научить ваше приложение считывать эту информацию и создавать в соответствие с нею экземпляры опубликованных подключаемых модулей.
Шаг 5. Синтаксический анализ файла конфигурации с использованием IConfigurationSectionHandler Чтобы провести синтаксический анализ подключаемых модулей, обнаруженных в файле .config приложения, инфраструктура предлагает очень простой механизм, позволяющий вам регистрировать определенный класса в качестве обработчика определенной части вашего файла конфигурации. У вас должен быть обработчик любой части файла, для которой инфраструктура не проводит автоматического синтаксического анализа; в противном случае, возникнет ConfigurationException. Чтобы обеспечить класс, проводящий синтаксический разбор секции подключаемых модулей, вам всего лишь надо реализовать интерфейс System.Configuration.IConfigurationSectionHandler. Сам по себе этот интерфейс очень прост: public interface IConfigurationSectionHandler { public object Create(object parent, object configContext, System.Xml.XmlNode section); } Все, что вам надо сделать — переопределить метод Create в своем специальном классе и провести синтаксический разбор XML-узла, предоставленного вам. Этот XML-узел, в данном случае, будет XML-узлом «Подключаемые модули» («Plugins»). После этого у вас есть вся информация, необходимая для создания экземпляра подключаемых модулей для вашего приложения. Ваш специальный класс должен поставлять стандартный конструктор, поскольку его экземпляр создается инфраструктурой автоматически во время выполнения, а затем вызывается его метод Create. Вот код для класса PluginSectionHandler: public class PluginSectionHandler:IConfigurationSectionHandler { public PluginSectionHandler() { } public object Create(object parent, object configContext, System.Xml.XmlNode section) { PluginCollection plugins = new PluginCollection(); foreach(XmlNode node in section.ChildNodes) { ... } return plugins; } } Как видите, в упомянутом ранее файле конфигурации вы предоставляете данные, необходимые инфраструктуре для обработки секции подключаемых модулей, используя тэг configSection перед тэгами самих подключаемых модулей. <configuration> <configSections> <section name="plugins" type="Royo.PluggableApp.PluginSectionHandler, PluggableApp" /> </configSections> ...
Обратите внимание, как определять класс. Строка состоит из двух частей: полного имени класса (включая пространство имен), запятой, имени сборки, в которой размещается этот класс. Это все, что нужно инфраструктуре для создания экземпляра класса, и не удивительно, что именно эта информация нужна и при регистрации любого подключаемого модуля для вашего приложения.
|