Command
Шаблон кастомной команды
Шаблон описания кастомной команды в серверном xml-файле:
В качестве значения атрибута Assembly
указывается имя кастомной сборки, в которой реализована команда. А в атрибуте Type
указывается имя класса, описывающего команду.
На сервере команды разделены на две части: инициируемая часть и исполняемая часть. Инициируемая часть представляется классом AbstractCommand, а исполняемая часть - AbstractCommandExecutor. Инициируемая часть используется для парсинга xml-кода, а исполняемая часть - для выполнения бизнес-логики.
Инициируемая часть
Шаблон кода инициируемой части:
Метод Init() принимает параметр XmlNode node, который соответствует тэгу <Command>
, описанному в xml-файле формы. Из объекта node можем получить информацию обо всех вложенных тэгах и их атрибутах. Значения, полученные из xml, сохраняются в публичные свойства, доступ к которым будет у исполняемой части через прямую ссылку на экземпляр класса CustomCommand, переданную в конструктор класса CustomCommandExecutor.
Исполняемая часть
Пример кода исполняемой части:
Метод Execute принимает параметр parameters типа IParameterized, хранящий контекст параметров, общий для всех команд. Из контекста можно получить словарь параметров, который можно использовать для подстановки значений в SQL-запросы вместо переменных.
Как это работает
При старте сервер разбирает серверный xml-файл и создает экземпляр класса CustomCommand для каждого тэга <Command>
типа CustomCommand. Когда происходит вызов команды, первым делом выполняется метод CreateExecutor из класса CustomCommand, который создает экземпляр класса CustomCommandExecutor.
Элементы команды
SQL-запросы
Пример команды с указанием текста SQL-запроса:
Инициируемая часть
Для получения значения обязательного тэга в методе Init необходимо использовать статический метод GetRequiredElementValue класса XmlParser:
Вторым параметром (string path) указывается полный путь до тэга, значение которого нужно получить. В третьем параметре (string name) указывается имя объекта, в котором происходит получение значения, в четвертом параметре (object targetObject) - класс объекта, в котором происходит получение значения. Имя объекта и его класс используются в формировании текста сообщения об ошибке. В качестве результата метод возвращает строку. Если элемент отсутствует, будет возвращено исключение типа InvalidXmlException.
Если необходимо получить значение необязательного элемента, то следует использовать метод GetElementValue. Этот метод в случае отсутствия элемента будет возвращать значение по умолчанию, переданное в параметрах метода.
Исполняемая часть
Если команда должна работать с SQL-запросами, то в конструкторе CustomCommandExecutor, используя статический метод GetRequiredService класса ServiceProvider, необходимо получить ссылки на сервисы обеспечивающие работу с базой данных.
Первый сервис - объект типа IDatabaseConnection, который устанавливает соединение с базой данных и выполняет SQL-запрос:
Второй сервис - объект типа ISqlQueryHelper, который помогает построить текст запроса, заменив в нем переменные в круглых скобках {}
на нужные значения из словаря параметров:
Для выполнения SQL-запросов в методе Execute используем метод ExecuteQueryAsync у объекта типа IDatabaseConnection, результатом которого будет объект типа DataTable:
В метод передается текст SQL-запроса, в котором при необходимости заменяются переменные на значения параметров из словаря, для этого используется сервис ISqlQueryHelper.
Команды
Пример описания кастомной команды, которая принимает имя другой команды, чтобы использовать ее результат выполнения или вызвать ее для выполнения, передав в нее свои значения:
В примере рассматривается команда AnySqlQueryCommand типа SqlQueryCommand, но это может быть команда любого типа, в том числе и кастомного. Вызов команды AnySqlQueryCommand можно реализовать в xml-файле перед вызовом команды MyCustomCommand, либо перенести в исходный код кастомки.
Инициируемая часть
Для получения значения обязательного атрибута тэга в методе Init необходимо использовать статический метод GetRequiredAttributeValue класса XmlParser:
Вторым параметром (string path) указывается полный путь до тэга, значение атрибута которого нужно получить. Имя атрибута указывается в третьем параметре (string attribute). В данном случае используется константа NAME_ATTRIBUTE
, описанная в базовом классе. Если элемент или его атрибут отсутствует, будет возвращено исключение типа InvalidXmlException.
Если необходимо получить значение необязательного атрибута, то следует использовать метод GetAttributeValue. Этот метод в случае отсутствия элемента или его атрибута будет возвращать значение по умолчанию, переданное в параметрах метода.
Исполняемая часть
При работе с командой первым делом нужно получить ее Executor:
Через свойство WorkflowType нашей команды получаем текущий процесс, у которого с помощью метода GetCommandExecutor получаем Executor нужной команды по ее имени.
Результат выполнения команды храниться в свойстве Value:
Так как в примере команда AnyCommandName имеет тип SqlQueryCommand, то ее результат можно привести к типу DataTable, что облегчит его обработку.
Но, прежде чем использовать результат выполнения команды, проверяем значение свойства Value. И если там пусто, то выполняем команду, вызвав метод Execute и передав в него параметры:
Логирование
Для возможности добавления записей в журнал событий Windows необходимо получить сервис ILogger, для этого в конструкторе CustomCommandExecutor используем статический метод GetService класса ServiceProvider.
Чтобы записать в журнал событий сообщение об ошибке, необходимо вызвать метод LogError:
Есть разные уровни сообщений для записи в журнал событий:
LogCritical() - форматирует и записывает критическое сообщение журнала;
LogDebug() - форматирует и записывает в журнал сообщение отладки;
LogError() - форматирует и записывает в журнал сообщение об ошибке;
LogInformation() - форматирует и записывает в журнал информационное сообщение;
LogTrace() - форматирует и записывает в журнал сообщение трассировки;
LogWarning() - форматирует и записывает в журнал сообщение с предупреждением.
Last updated